[javascript] 문자열을 Bytearray로 변환하는 방법

JavaScript를 사용하여 바이트 배열의 문자열을 어떻게 변환 할 수 있습니까? 출력은 아래 C # 코드와 동일해야합니다.

UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);

UnicodeEncoding은 기본적으로 Little-Endianness를 사용하는 UTF-16입니다.

편집 : 위의 C # 코드를 사용하여 bytearray 생성 클라이언트 측과 서버 측에서 생성 된 클라이언트 측을 일치시켜야하는 요구 사항이 있습니다.



답변

C #에서 이것을 실행

UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes("Hello");

다음으로 배열을 만듭니다.

72,0,101,0,108,0,108,0,111,0

바이트 배열

코드가 255보다 큰 문자의 경우 다음과 같습니다.

바이트 배열

JavaScript에서 매우 유사한 동작을 원한다면 이렇게 할 수 있습니다 (v2는 좀 더 강력한 솔루션이지만 원래 버전은 0x00 ~ 0xff에서만 작동합니다)

var str = "Hello竜";
var bytes = []; // char codes
var bytesv2 = []; // char codes

for (var i = 0; i < str.length; ++i) {
  var code = str.charCodeAt(i);

  bytes = bytes.concat([code]);

  bytesv2 = bytesv2.concat([code & 0xff, code / 256 >>> 0]);
}

// 72, 101, 108, 108, 111, 31452
console.log('bytes', bytes.join(', '));

// 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 220, 122
console.log('bytesv2', bytesv2.join(', '));


답변

node.js에서 작동하는 솔루션을 찾고 있다면 다음을 사용할 수 있습니다.

var myBuffer = [];
var str = 'Stack Overflow';
var buffer = new Buffer(str, 'utf16le');
for (var i = 0; i < buffer.length; i++) {
    myBuffer.push(buffer[i]);
}

console.log(myBuffer);


답변

C #과 Java가 동일한 바이트 배열을 생성한다고 가정합니다. ASCII가 아닌 문자가있는 경우 0을 추가하는 것으로는 충분하지 않습니다.이 예제에는 몇 가지 특수 문자가 포함되어 있습니다.

var str = "Hell ö € Ω ?";
var bytes = [];
var charCode;

for (var i = 0; i < str.length; ++i)
{
    charCode = str.charCodeAt(i);
    bytes.push((charCode & 0xFF00) >> 8);
    bytes.push(charCode & 0xFF);
}

alert(bytes.join(' '));
// 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30

C #이 BOM (Byte Order Marks)을 배치하는지 여부는 모르겠지만 UTF-16을 사용하는 경우 Java String.getBytes는 254255 바이트를 추가합니다.

String s = "Hell ö € Ω ";
// now add a character outside the BMP (Basic Multilingual Plane)
// we take the violin-symbol (U+1D11E) MUSICAL SYMBOL G CLEF
s += new String(Character.toChars(0x1D11E));
// surrogate codepoints are: d834, dd1e, so one could also write "\ud834\udd1e"

byte[] bytes = s.getBytes("UTF-16");
for (byte aByte : bytes) {
    System.out.print((0xFF & aByte) + " ");
}
// 254 255 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30

편집하다:

특수 문자 (U + 1D11E) MUSICAL SYMBOL G CLEF (BPM 외부에 추가되었으므로 UTF-16에서 2 바이트뿐 아니라 4 바이트도 사용함)

현재 JavaScript 버전은 내부적으로 “UCS-2″를 사용하므로이 기호는 2 개의 일반 문자 공간을 차지합니다.

확실하지 않지만 사용할 때 charCodeAtUTF-16에서도 사용되는 대리 코드 포인트를 정확히 얻는 것 같으므로 비 BPM 문자가 올바르게 처리됩니다.

이 문제는 절대적으로 중요하지 않습니다. 사용 된 JavaScript 버전 및 엔진에 따라 다를 수 있습니다. 따라서 신뢰할 수있는 솔루션을 원한다면 다음을 살펴 봐야합니다.


답변

2018 년 가장 쉬운 방법은 TextEncoder 이지만 반환 된 요소는 바이트 배열이 아니라 Uint8Array입니다. (모든 브라우저가 지원하는 것은 아닙니다)

let utf8Encode = new TextEncoder();
utf8Encode.encode("eee")
> Uint8Array [ 101, 101, 101 ]


답변

UTF-16 바이트 배열

JavaScript는 C #과 마찬가지로 문자열을 UTF-16 으로 인코딩 UnicodeEncoding하므로 바이트 배열은 다음과 같이를 사용 charCodeAt()하고 반환 된 각 바이트 쌍을 2 개의 개별 바이트로 분할 하여 정확히 일치해야합니다 .

function strToUtf16Bytes(str) {
  const bytes = [];
  for (ii = 0; ii < str.length; ii++) {
    const code = str.charCodeAt(ii); // x00-xFFFF
    bytes.push(code & 255, code >> 8); // low, high
  }
  return bytes;
}

예를 들면 :

strToUtf16Bytes('?');
// [ 60, 216, 53, 223 ]

그러나 UTF-8 바이트 배열을 얻으려면 바이트를 트랜스 코딩해야합니다.

UTF-8 바이트 배열

솔루션은 다소 사소한 느낌이 들지 않지만 트래픽이 많은 프로덕션 환경에서 큰 성공을 거둔 아래 코드를 사용했습니다 ( 원본 소스 ).

또한 관심있는 독자 를 위해 PHP와 같은 다른 언어에서보고되는 문자열 길이로 작업하는 데 도움 이되는 유니 코드 도우미 를 게시했습니다 .

/**
 * Convert a string to a unicode byte array
 * @param {string} str
 * @return {Array} of bytes
 */
export function strToUtf8Bytes(str) {
  const utf8 = [];
  for (let ii = 0; ii < str.length; ii++) {
    let charCode = str.charCodeAt(ii);
    if (charCode < 0x80) utf8.push(charCode);
    else if (charCode < 0x800) {
      utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
    } else if (charCode < 0xd800 || charCode >= 0xe000) {
      utf8.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
    } else {
      ii++;
      // Surrogate pair:
      // UTF-16 encodes 0x10000-0x10FFFF by subtracting 0x10000 and
      // splitting the 20 bits of 0x0-0xFFFFF into two halves
      charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (str.charCodeAt(ii) & 0x3ff));
      utf8.push(
        0xf0 | (charCode >> 18),
        0x80 | ((charCode >> 12) & 0x3f),
        0x80 | ((charCode >> 6) & 0x3f),
        0x80 | (charCode & 0x3f),
      );
    }
  }
  return utf8;
}


답변

@hgoebl의 답변에서 영감을 얻었습니다. 그의 코드는 UTF-16 용이며 US-ASCII 용이 필요했습니다. 따라서 US-ASCII, UTF-16 및 UTF-32를 다루는 더 완전한 답변이 있습니다.

/**@returns {Array} bytes of US-ASCII*/
function stringToAsciiByteArray(str)
{
    var bytes = [];
   for (var i = 0; i < str.length; ++i)
   {
       var charCode = str.charCodeAt(i);
      if (charCode > 0xFF)  // char > 1 byte since charCodeAt returns the UTF-16 value
      {
          throw new Error('Character ' + String.fromCharCode(charCode) + ' can\'t be represented by a US-ASCII byte.');
      }
       bytes.push(charCode);
   }
    return bytes;
}
/**@returns {Array} bytes of UTF-16 Big Endian without BOM*/
function stringToUtf16ByteArray(str)
{
    var bytes = [];
    //currently the function returns without BOM. Uncomment the next line to change that.
    //bytes.push(254, 255);  //Big Endian Byte Order Marks
   for (var i = 0; i < str.length; ++i)
   {
       var charCode = str.charCodeAt(i);
       //char > 2 bytes is impossible since charCodeAt can only return 2 bytes
       bytes.push((charCode & 0xFF00) >>> 8);  //high byte (might be 0)
       bytes.push(charCode & 0xFF);  //low byte
   }
    return bytes;
}
/**@returns {Array} bytes of UTF-32 Big Endian without BOM*/
function stringToUtf32ByteArray(str)
{
    var bytes = [];
    //currently the function returns without BOM. Uncomment the next line to change that.
    //bytes.push(0, 0, 254, 255);  //Big Endian Byte Order Marks
   for (var i = 0; i < str.length; i+=2)
   {
       var charPoint = str.codePointAt(i);
       //char > 4 bytes is impossible since codePointAt can only return 4 bytes
       bytes.push((charPoint & 0xFF000000) >>> 24);
       bytes.push((charPoint & 0xFF0000) >>> 16);
       bytes.push((charPoint & 0xFF00) >>> 8);
       bytes.push(charPoint & 0xFF);
   }
    return bytes;
}

UTF-8은 가변 길이이며 인코딩을 직접 작성해야하기 때문에 포함되지 않습니다. UTF-8 및 UTF-16은 가변 길이입니다. UTF-8, UTF-16 및 UTF-32에는 이름에서 알 수 있듯이 최소 비트 수가 있습니다. UTF-32 문자의 코드 포인트가 65이면 앞에 0이 3 개 있음을 의미합니다. 그러나 UTF-16에 대한 동일한 코드는 0으로 시작됩니다. 반면에 US-ASCII는 고정 너비 8 비트이므로 바이트로 직접 변환 할 수 있습니다.

String.prototype.charCodeAt최대 2 바이트를 반환하고 UTF-16과 정확히 일치합니다. 그러나 String.prototype.codePointAtECMAScript 6 (Harmony) 제안의 일부인 UTF-32 가 필요합니다. charCodeAt은 US-ASCII가 나타낼 수있는 것보다 더 많은 가능한 문자 인 2 바이트를 반환하기 때문에 stringToAsciiByteArray이러한 경우에는 문자를 반으로 나누고 하나 또는 두 바이트를 모두 취하는 대신 함수 가 throw됩니다.

문자 인코딩이 중요하지 않기 때문에이 대답은 중요하지 않습니다. 원하는 바이트 배열의 종류는 해당 바이트를 나타내는 문자 인코딩에 따라 다릅니다.

javascript에는 내부적으로 UTF-16 또는 UCS-2를 사용하는 옵션이 있지만 UTF-16처럼 작동하는 메서드가 있기 때문에 모든 브라우저가 UCS-2를 사용하는 이유를 알 수 없습니다. 참조 : https://mathiasbynens.be/notes/javascript-encoding

예, 질문이 4 년이라는 것을 알고 있지만이 답변이 필요했습니다.


답변

답변에 대해 언급 할 수 없기 때문에 진 이즈 래엘의 답변을 바탕으로

var myBuffer = [];
var str = 'Stack Overflow';
var buffer = new Buffer(str, 'utf16le');
for (var i = 0; i < buffer.length; i++) {
    myBuffer.push(buffer[i]);
}

console.log(myBuffer);

브라우저에서 Node.js 버퍼를 사용하려면 이것을 사용할 수 있다고 말함으로써.

https://github.com/feross/buffer

따라서 Tom Stickel의 반대는 유효하지 않으며 그 대답은 실제로 유효한 대답입니다.