서버에서 UTF-8로 전송 될 때 약 500K의 자바 스크립트 문자열이 있습니다. JavaScript에서 크기를 어떻게 알 수 있습니까?
JavaScript는 UCS-2를 사용하므로 문자 당 2 바이트를 의미합니다. 그러나 JavaScript 구현에 의존합니까? 아니면 페이지 인코딩 또는 콘텐츠 유형?
서버에서 UTF-8로 전송 될 때 약 500K의 자바 스크립트 문자열이 있습니다. JavaScript에서 크기를 어떻게 알 수 있습니까?
JavaScript는 UCS-2를 사용하므로 문자 당 2 바이트를 의미합니다. 그러나 JavaScript 구현에 의존합니까? 아니면 페이지 인코딩 또는 콘텐츠 유형?
답변:
String
값은 구현에 의존하지는 따라 ECMA-262 3 판 사양 , 각 문자는 대표 UTF-16 텍스트의 단일 16 비트 단위 :
4.3.16 문자열 값
문자열 값은 String 유형의 멤버이며 0 개 이상의 16 비트 부호없는 정수 값의 유한 순서 시퀀스입니다.
참고 각 값은 일반적으로 UTF-16 텍스트의 단일 16 비트 단위를 나타내지 만 언어는 16 비트 부호없는 정수라는 점을 제외하고 값에 제한이나 요구 사항을 적용하지 않습니다.
이 함수는 전달한 UTF-8 문자열의 바이트 크기를 반환합니다.
function byteCount(s) {
return encodeURI(s).split(/%..|./).length - 1;
}
JavaScript 엔진은 내부적으로 UCS-2 또는 UTF-16을 무료로 사용할 수 있습니다. 내가 아는 대부분의 엔진은 UTF-16을 사용하지만 어떤 선택을하더라도 언어의 특성에 영향을주지 않는 구현 세부 사항 일뿐입니다.
그러나 ECMAScript / JavaScript 언어 자체는 UTF-16이 아닌 UCS-2에 따라 문자를 노출합니다.
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)
대신 사용하십시오 . "% uXXXX"로 인코딩하는 문자열에 대해 스 니펫이 실패합니다.
node.js를 사용하는 경우 버퍼를 사용하는 더 간단한 솔루션이 있습니다 .
function getBinarySize(string) {
return Buffer.byteLength(string, 'utf8');
}
이에 대한 npm lib가 있습니다 : https://www.npmjs.org/package/utf8-binary-cutter (신실하게)
Blob 을 사용하여 문자열 크기 (바이트)를 가져올 수 있습니다 .
예 :
console.info(
new Blob(['😂']).size, // 4
new Blob(['👍']).size, // 4
new Blob(['😂👍']).size, // 8
new Blob(['👍😂']).size, // 8
new Blob(['I\'m a string']).size, // 12
// from Premasagar correction of Lauri's answer for
// strings containing lone characters in the surrogate pair range:
// https://stackoverflow.com/a/39488643/6225838
new Blob([String.fromCharCode(55555)]).size, // 3
new Blob([String.fromCharCode(55555, 57000)]).size // 4 (not 6)
);
Buffer.from('😂').length
unescape js 함수 를 사용하여 다음 조합을 시도하십시오 .
const byteAmount = unescape(encodeURIComponent(yourString)).length
전체 인코딩 프로세스 예 :
const s = "1 a ф № @ ®"; //length is 11
const s2 = encodeURIComponent(s); //length is 41
const s3 = unescape(s2); //length is 15 [1-1,a-1,ф-2,№-3,@-1,®-2]
const s4 = escape(s3); //length is 39
const s5 = decodeURIComponent(s4); //length is 11
unescape
자바 스크립트 함수는 사용되지 않으며 균일 자원 식별자 (URI)를 디코딩하는 데 사용되어서는 안된다. 출처
unescape
를 디코딩 하는 데 사용되지 않습니다 . %xx
시퀀스를 단일 문자 로 변환하는 데 사용됩니다 . As encodeURIComponent
는 해당 ASCII 문자 또는 %xx
시퀀스 로 코드 단위를 나타내는 UTF-8로 문자열을 인코딩합니다 . 호출 하면 원래 문자열의 UTF-8 표현을 포함 unescape(encodeURIComponent(...))
하는 이진 문자열 이 생성됩니다. .length
올바르게 호출 하면 UTF-8로 인코딩 된 문자열의 크기 (바이트)가 제공됩니다.
un
) escape
는 1999 년부터 더 이상 사용되지 않지만 모든 브라우저에서 계속 사용할 수 있습니다 ...-즉, 더 이상 사용하지 않을 이유가 있습니다. 기본적으로 올바르게 사용할 수있는 방법은 없습니다 ( en
-/ decodeURI
( Component
) 와 함께 UTF8 인코딩 / 디코딩 제외 ) 또는 적어도 ( un
)에 대한 다른 유용한 응용 프로그램을 알지 못합니다 escape
. 그리고 오늘날에는 UTF8 ( TextEncoder
등) 을 인코딩 / 디코딩하는 더 나은 대안이 있습니다
node.js를 대상으로하는 경우 다음을 사용할 수 있습니다 Buffer.from(string).length
.
var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)
UTF-8은 코드 포인트 당 1-4 바이트를 사용하여 문자를 인코딩합니다. CMS가 수락 된 답변에서 지적했듯이 JavaScript는 16 비트 (2 바이트)를 사용하여 각 문자를 내부적으로 저장합니다.
루프를 통해 문자열의 각 문자를 구문 분석하고 코드 포인트 당 사용 된 바이트 수를 계산 한 다음 총 개수에 2를 곱하면 해당 UTF-8 인코딩 문자열에 대한 JavaScript의 메모리 사용량 (바이트)이 있어야합니다. 아마도 다음과 같습니다.
getStringMemorySize = function( _string ) {
"use strict";
var codePoint
, accum = 0
;
for( var stringIndex = 0, endOfString = _string.length; stringIndex < endOfString; stringIndex++ ) {
codePoint = _string.charCodeAt( stringIndex );
if( codePoint < 0x100 ) {
accum += 1;
continue;
}
if( codePoint < 0x10000 ) {
accum += 2;
continue;
}
if( codePoint < 0x1000000 ) {
accum += 3;
} else {
accum += 4;
}
}
return accum * 2;
}
예 :
getStringMemorySize( 'I' ); // 2
getStringMemorySize( '❤' ); // 4
getStringMemorySize( '𠀰' ); // 8
getStringMemorySize( 'I❤𠀰' ); // 14
Pre-ES6
항상 문자 당 2 바이트. 사양에 "값은 16 비트 부호없는 정수 여야합니다"라고되어 있으므로 UTF-16은 허용되지 않습니다. UTF-16 문자열은 3 바이트 또는 4 바이트 문자를 사용할 수 있으므로 2 바이트 요구 사항을 위반합니다. 결정적으로 UTF-16을 완전히 지원할 수는 없지만 표준에서는 사용되는 2 바이트 문자가 유효한 UTF-16 문자 여야합니다. 즉, Pre-ES6 JavaScript 문자열은 UTF-16 문자의 하위 집합을 지원합니다.
ES6
이상 문자 당 2 바이트 또는 문자 당 5 바이트 이상. ES6 (ECMAScript 6)은 유니 코드 코드 포인트 이스케이프에 대한 지원을 추가하기 때문에 추가 크기가 적용됩니다 . 유니 코드 이스케이프 사용은 다음과 같습니다. \ u {1D306}
실용적인 메모
이것은 특정 엔진의 내부 구현과 관련이 없습니다. 예를 들어 일부 엔진은 완전한 UTF-16 지원과 함께 데이터 구조와 라이브러리를 사용하지만 외부에서 제공하는 것이 완전한 UTF-16 지원 일 필요는 없습니다. 또한 엔진은 외부 UTF-16 지원도 제공 할 수 있지만 그렇게해야하는 것은 아닙니다.
ES6의 경우, 최신 버전의 유니 코드에는 3 바이트에 쉽게 들어갈 수있는 136,755 개의 가능한 문자 만 있기 때문에 실제로 말하는 문자의 길이는 5 바이트 (이스케이프 지점의 경우 2 바이트 + 유니 코드 코드 지점의 경우 3 바이트)를 넘지 않습니다. 그러나 이것은 기술적으로 표준에 의해 제한되지 않으므로 원칙적으로 단일 문자는 코드 포인트에 4 바이트, 총 6 바이트를 사용할 수 있습니다.
여기에서 바이트 크기를 계산하기위한 대부분의 코드 예제는 ES6 유니 코드 코드 포인트 이스케이프를 고려하지 않는 것 같으므로 경우에 따라 결과가 올바르지 않을 수 있습니다.
Buffer.from('test').length
와 Buffer.byteLength('test')
같 new Blob(['test']).size
습니까?
'\u{1F600}'.length===2
, '\u{1F600}'==='\uD83D\uDE00'
, '\u{1F600}'==='😀'
)
JavaScript 문자열의 단일 요소는 단일 UTF-16 코드 단위로 간주됩니다. 즉, 문자열 문자는 16 비트 (1 코드 단위)로 저장되고 16 비트는 2 바이트 (8 비트 = 1 바이트)와 같습니다.
이 charCodeAt()
메서드는 지정된 인덱스에서 UTF-16 코드 단위를 나타내는 0에서 65535 사이의 정수를 반환하는 데 사용할 수 있습니다.
는 codePointAt()
유니 코드 문자 (예 : UTF-32)의 전체 코드 포인트 값을 반환하는 데 사용할 수 있습니다.
UTF-16 문자를 단일 16 비트 코드 단위로 표현할 수없는 경우 서로 게이트 쌍이 있으므로 두 개의 코드 단위 (2 x 16 비트 = 4 바이트)를 사용합니다.
다른 인코딩 및 해당 코드 범위는 유니 코드 인코딩 을 참조하십시오 .
Lauri Oherd의 대답은 야생에서 볼 수있는 대부분의 문자열에서 잘 작동하지만 문자열이 서로 게이트 쌍 범위 (0xD800 ~ 0xDFFF)에 고독한 문자를 포함하면 실패합니다. 예
byteCount(String.fromCharCode(55555))
// URIError: URI malformed
이 더 긴 함수는 모든 문자열을 처리해야합니다.
function bytes (str) {
var bytes=0, len=str.length, codePoint, next, i;
for (i=0; i < len; i++) {
codePoint = str.charCodeAt(i);
// Lone surrogates cannot be passed to encodeURI
if (codePoint >= 0xD800 && codePoint < 0xE000) {
if (codePoint < 0xDC00 && i + 1 < len) {
next = str.charCodeAt(i + 1);
if (next >= 0xDC00 && next < 0xE000) {
bytes += 4;
i++;
continue;
}
}
}
bytes += (codePoint < 0x80 ? 1 : (codePoint < 0x800 ? 2 : 3));
}
return bytes;
}
예
bytes(String.fromCharCode(55555))
// 3
서로 게이트 쌍을 포함하는 문자열의 크기를 올바르게 계산합니다.
bytes(String.fromCharCode(55555, 57000))
// 4 (not 6)
결과는 Node의 내장 함수와 비교할 수 있습니다 Buffer.byteLength
.
Buffer.byteLength(String.fromCharCode(55555), 'utf8')
// 3
Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8')
// 4 (not 6)
V8 엔진의 임베디드 버전으로 작업하고 있습니다. 단일 문자열을 테스트했습니다. 각 단계를 1000 자 밀어냅니다. UTF-8.
1 바이트 (8 비트, ANSI) 문자 "A"(16 진수 : 41)를 사용한 첫 번째 테스트. 두 번째 테스트는 2 바이트 문자 (16 비트) "Ω"(16 진수 : CE A9)이고 세 번째 테스트는 3 바이트 문자 (24 비트) "☺"(16 진수 : E2 98 BA)입니다.
세 가지 경우 모두 장치는 888,000 자 및 ca를 사용하여 메모리 부족을 인쇄합니다. 26348kb의 RAM.
결과 : 문자가 동적으로 저장되지 않습니다. 그리고 16 비트 만이 아닙니다. -좋습니다. 아마도 제 경우에만 해당됩니다 (내장형 128MB RAM 장치, V8 엔진 C ++ / QT).-문자 인코딩은 자바 스크립트 엔진의 RAM 크기와 관련이 없습니다. 예를 들어 encodingURI 등은 높은 수준의 데이터 전송 및 저장에만 유용합니다.
포함 여부에 관계없이 문자는 16 비트에만 저장되지 않습니다. 불행히도 저수준 영역에서 Javascript가 수행하는 작업에 대한 100 % 대답은 없습니다. Btw. 문자 "A"의 배열로 동일한 (위의 첫 번째 테스트)을 테스트했습니다. 매 단계마다 1000 개 항목을 푸시했습니다. (정확히 동일한 테스트입니다. 방금 문자열을 배열로 교체했습니다.) 시스템은 10416KB를 사용하고 배열 길이가 1,337,000 인 후에 메모리에서 빠져 나옵니다 (원함). 따라서 자바 스크립트 엔진은 간단하게 제한되지 않습니다. 좀 더 복잡합니다.
이것을 시도 할 수 있습니다.
var b = str.match(/[^\x00-\xff]/g);
return (str.length + (!b ? 0: b.length));
그것은 나를 위해 일했습니다.