JavaScript 문자열은 몇 바이트입니까?


98

서버에서 UTF-8로 전송 될 때 약 500K의 자바 스크립트 문자열이 있습니다. JavaScript에서 크기를 어떻게 알 수 있습니까?

JavaScript는 UCS-2를 사용하므로 문자 당 2 바이트를 의미합니다. 그러나 JavaScript 구현에 의존합니까? 아니면 페이지 인코딩 또는 콘텐츠 유형?


대략. 대답은 길이 * 문자 크기이므로 추측이 가깝습니다.
glasnt

1
예를 들어 ES6와 같은 최신 JavaScript는 UCS-2 만 사용하지 않습니다. 자세한 내용은 다음을 참조하십시오. stackoverflow.com/a/46735247/700206
whitneyland

답변:


37

String값은 구현에 의존하지는 따라 ECMA-262 3 판 사양 , 각 문자는 대표 UTF-16 텍스트의 단일 16 비트 단위 :

4.3.16 문자열 값

문자열 값은 String 유형의 멤버이며 0 개 이상의 16 비트 부호없는 정수 값의 유한 순서 시퀀스입니다.

참고 각 값은 일반적으로 UTF-16 텍스트의 단일 16 비트 단위를 나타내지 만 언어는 16 비트 부호없는 정수라는 점을 제외하고 값에 제한이나 요구 사항을 적용하지 않습니다.


8
그 구절을 읽었다 고해서 실행 독립성을 의미하지는 않습니다.
Paul Biggar

4
UTF-16은 보장되지 않으며 16 비트 정수로 저장된 문자열 만 있습니다.
bjornl

UTF-16과 관련하여 구현에 따라 다릅니다. 16 비트 문자 설명은 보편적입니다.
Panzercrisis

1
나는 파이어 폭스도 .... 어떤 문자열을 문자 당 1 바이트를 사용할 수 내부적으로 생각 blog.mozilla.org/javascript/2014/07/21/...
마이클 Charemza

1
UTF-16은 내가 읽는 방식대로 명시 적으로 허용되지 않습니다 . UTF-16 문자는 최대 4 바이트를 가질 수 있지만 사양에 "값은 16 비트 부호없는 정수 여야합니다"라고 나와 있습니다. 즉, JavaScript 문자열 값은 UTF-16의 하위 집합이지만 3 바이트 또는 4 바이트 문자를 사용하는 UTF-16 문자열은 허용되지 않습니다.
whitneyland

71

이 함수는 전달한 UTF-8 문자열의 바이트 크기를 반환합니다.

function byteCount(s) {
    return encodeURI(s).split(/%..|./).length - 1;
}

출처

JavaScript 엔진은 내부적으로 UCS-2 또는 UTF-16을 무료로 사용할 수 있습니다. 내가 아는 대부분의 엔진은 UTF-16을 사용하지만 어떤 선택을하더라도 언어의 특성에 영향을주지 않는 구현 세부 사항 일뿐입니다.

그러나 ECMAScript / JavaScript 언어 자체는 UTF-16이 아닌 UCS-2에 따라 문자를 노출합니다.

출처


9
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)대신 사용하십시오 . "% uXXXX"로 인코딩하는 문자열에 대해 스 니펫이 실패합니다.
Rob W

웹 소켓 프레임의 크기 계산에 사용되며, 크롬 개발 도구와 동일한 크기의 문자열 프레임을 제공합니다.
user85155

2
s3에 업로드 된 자바 스크립트 문자열에 사용되며 s3는 정확히 동일한 크기를 표시합니다 [(byteCount (s)) / 1024) .toFixed (2) + "KiB"]
user85155


44

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)
);


3
얼룩에 대해 신에게 감사합니다! 이것은 아마도 최신 브라우저에서 허용되는 대답 일 것입니다.
prasanthv

Node.js에서 Blob을 가져 오는 방법은 무엇입니까?
Alexander Mills

5
아, Node.js를 함께 우리는 예를 들어 버퍼 사용Buffer.from('😂').length
알렉산더 밀스

19

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

4
unescape자바 스크립트 함수는 사용되지 않으며 균일 자원 식별자 (URI)를 디코딩하는 데 사용되어서는 안된다. 출처
Lauri Oherd 2012 년

@LauriOherd 나는 주석이 오래되었다는 것을 알고 있지만 :이 답변에서는 URI unescape디코딩 하는 데 사용되지 않습니다 . %xx시퀀스를 단일 문자 로 변환하는 데 사용됩니다 . As encodeURIComponent는 해당 ASCII 문자 또는 %xx시퀀스 로 코드 단위를 나타내는 UTF-8로 문자열을 인코딩합니다 . 호출 하면 원래 문자열의 UTF-8 표현을 포함 unescape(encodeURIComponent(...))하는 이진 문자열 이 생성됩니다. .length올바르게 호출 하면 UTF-8로 인코딩 된 문자열의 크기 (바이트)가 제공됩니다.
TS

그리고 예 ( un) escape는 1999 년부터 더 이상 사용되지 않지만 모든 브라우저에서 계속 사용할 수 있습니다 ...-즉, 더 이상 사용하지 않을 이유가 있습니다. 기본적으로 올바르게 사용할 수있는 방법은 없습니다 ( en-/ decodeURI( Component) 와 함께 UTF8 인코딩 / 디코딩 제외 ) 또는 적어도 ( un)에 대한 다른 유용한 응용 프로그램을 알지 못합니다 escape. 그리고 오늘날에는 UTF8 ( TextEncoder등) 을 인코딩 / 디코딩하는 더 나은 대안이 있습니다
TS

10

node.js를 대상으로하는 경우 다음을 사용할 수 있습니다 Buffer.from(string).length.

var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)

9

다음은 내가 사용하는 세 가지 방법입니다.

  1. TextEncoder ()

    (new TextEncoder().encode("myString")).length)

  2. 얼룩

    new Blob(["myString"]).size)

  3. 완충기

    Buffer.byteLength("myString", 'utf8'))


참고 : 코드 세그먼트 모두 끝에 짝이없는 닫는 괄호가있는 것 같습니다.
SamWN

7

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

5

JavaScript 문자열의 크기는 다음과 같습니다.

  • Pre-ES6 : 문자 당 2 바이트
  • ES6 이상 : 문자 당 2 바이트 또는 문자 당 5 바이트 이상

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 유니 코드 코드 포인트 이스케이프를 고려하지 않는 것 같으므로 경우에 따라 결과가 올바르지 않을 수 있습니다.


1
크기가 문자 당 2 바이트라면 왜 4 (노드에서)와 4 Buffer.from('test').lengthBuffer.byteLength('test')new Blob(['test']).size습니까?
user1063287

Pre-ES6 : UTF-16 허용 : ECMA-262 제 3 판 (1999 년부터) 참조 : 1 페이지에 UCS2 또는 UTF-16이 허용됩니다. 5 페이지, 문자열 값 정의 : "... 각 값은 일반적으로 UTF-16 텍스트의 단일 16 비트 단위를 나타내지 만 ...". 81 페이지에는 일치하는 서로 게이트 쌍을 4 개의 UTF-8 바이트로 인코딩하는 방법을 보여주는 표가 있습니다.
TS

"문자 별"- "사용자가 인식하는 문자"( spec , 간단한 설명 )에 따라 16 비트 코드 단위가 될 수 있습니다. "코드 포인트"를 의미하는 경우 UTF-16 으로 된 하나 또는 두 개의 16 비트 코드 단위가 될 수 있습니다 . (2.5 코드 단위가 될 수 없습니다 (또는 5 바이트를 어떻게 얻습니까?))
TS

자바 스크립트 문자열의 각 요소 ( 16 비트 부호없는 정수 값 ( "elements") )가 실제로 내부적으로 2 바이트로 표현 되는지 여부 는 표준에 정의되어 있지 않습니다. (그리고 어떻게 될 수 있었는지-자바 스크립트 프로그램에 제공된 인터페이스가 표준을 따르는 한 모든 것이 의도 한대로 작동합니다.) 예를 들어 Mozilla 는 문자열에 latin1 만 포함 된 경우 코드 포인트 당 1 바이트 만
TS

유니 코드 코드 포인트 이스케이프는 문자열 길이와 아무 관련이 없습니다. 소스 코드에서 문자열을 표현하는 새로운 방법 일뿐입니다. ( '\u{1F600}'.length===2, '\u{1F600}'==='\uD83D\uDE00', '\u{1F600}'==='😀')
TS

3

JavaScript 문자열의 단일 요소는 단일 UTF-16 코드 단위로 간주됩니다. 즉, 문자열 문자는 16 비트 (1 코드 단위)로 저장되고 16 비트는 2 바이트 (8 비트 = 1 바이트)와 같습니다.

charCodeAt()메서드는 지정된 인덱스에서 UTF-16 코드 단위를 나타내는 0에서 65535 사이의 정수를 반환하는 데 사용할 수 있습니다.

codePointAt()유니 코드 문자 (예 : UTF-32)의 전체 코드 포인트 값을 반환하는 데 사용할 수 있습니다.

UTF-16 문자를 단일 16 비트 코드 단위로 표현할 수없는 경우 서로 게이트 쌍이 있으므로 두 개의 코드 단위 (2 x 16 비트 = 4 바이트)를 사용합니다.

다른 인코딩 및 해당 코드 범위는 유니 코드 인코딩 을 참조하십시오 .


대리자에 대해 말하는 내용은 ECMA 스크립트 사양을 위반하는 것 같습니다. 위에서 언급했듯이 사양에는 문자 당 2 바이트가 필요하며 서로 게이트 쌍을 허용하면이를 위반합니다.
whitneyland

Javascript ES5 엔진은 내부적으로 USC-2 또는 UTF-16을 자유롭게 사용할 수 있지만 실제로 사용하는 것은 서로 게이트가있는 일종의 UCS-2입니다. 이는 서로 게이트 반쪽을 별도의 문자, 단일 UTF-16 부호없는 정수로 노출 할 수 있기 때문입니다. 하나 이상의 16 비트 코드 단위를 표시해야하는 소스 코드에서 유니 코드 문자를 사용하는 경우 서로 게이트 쌍이 사용됩니다. 이 동작은 사양 위반이 아닙니다. 6 장 소스 텍스트 참조 : ecma-international.org/ecma-262/5.1
holmberd

2

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)

1

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 인 후에 메모리에서 빠져 나옵니다 (원함). 따라서 자바 스크립트 엔진은 간단하게 제한되지 않습니다. 좀 더 복잡합니다.


0

이것을 시도 할 수 있습니다.

  var b = str.match(/[^\x00-\xff]/g);
  return (str.length + (!b ? 0: b.length)); 

그것은 나를 위해 일했습니다.


1
확실히 이것은 모든 문자가 최대 2 바이트라고 가정합니까? 3 바이트 또는 4 바이트 문자 (UTF-8에서 가능)가있는 경우이 함수는 2 바이트 문자로만 계산합니까?
Adam Burley
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.