Uint8Array เป็นสตริงใน Javascript


122

ฉันมีข้อมูลที่เข้ารหัส UTF-8 อยู่ในช่วงขององค์ประกอบ Uint8Array ใน Javascript มีวิธีที่มีประสิทธิภาพในการถอดรหัสสิ่งเหล่านี้เป็นสตริงจาวาสคริปต์ปกติหรือไม่ (ฉันเชื่อว่า Javascript ใช้ Unicode 16 บิต) ฉันไม่ต้องการเพิ่มอักขระหนึ่งตัวในเวลานั้นเนื่องจากการต่อสายอักขระจะกลายเป็น CPU ที่เข้มข้น


ถ้าไม่แน่ใจว่ามันจะทำงาน แต่ฉันจะใช้u8array.toString()เมื่อมีการอ่านไฟล์จาก BrowserFS ซึ่งอาจจะทำให้วัตถุ Uint8Array fs.readFileเมื่อคุณเรียก
jcubic

1
@jcubic สำหรับฉันtoStringในการUint8Arrayส่งคืนหมายเลขที่คั่นด้วยจุลภาคเช่น"91,50,48,49,57,45"(Chrome 79)
kolen

คำตอบ:


172

TextEncoderและTextDecoderจากมาตรฐานการเข้ารหัสซึ่งถูกเติมเต็มโดยไลบรารีการเข้ารหัสสตริงจะแปลงระหว่างสตริงและ ArrayBuffers:

var uint8array = new TextEncoder("utf-8").encode("¢");
var string = new TextDecoder("utf-8").decode(uint8array);

40
สำหรับใครที่ขี้เกียจอย่างฉันnpm install text-encoding, var textEncoding = require('text-encoding'); var TextDecoder = textEncoding.TextDecoder;. ไม่เป็นไรขอบคุณ.
Evan Hu

16
ระวังไลบรารีการเข้ารหัสข้อความ npm ตัววิเคราะห์บันเดิลของ
Webpack

3
@VincentScheib เบราว์เซอร์ลบการสนับสนุนสำหรับรูปแบบอื่น ๆ utf-8ยกเว้น ดังนั้นการTextEncoderโต้เถียงจึงไม่จำเป็น!
tripulse

1
nodejs.org/api/string_decoder.htmlจากตัวอย่าง: const {StringDecoder} = ต้องใช้ ('string_decoder'); ตัวถอดรหัส const = StringDecoder ใหม่ ('utf8'); const cent = Buffer.from ([0xC2, 0xA2]); console.log (decoder.write (ร้อยละ));
curist

4
โปรดทราบว่า Node.js ได้เพิ่มTextEncoder/ TextDecoderAPIs ใน v11 ดังนั้นจึงไม่จำเป็นต้องติดตั้งแพ็กเกจเพิ่มเติมใด ๆ หากคุณกำหนดเป้าหมายเวอร์ชันโหนดปัจจุบันเท่านั้น
Loilo

42

สิ่งนี้ควรใช้งานได้:

// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0
 * LastModified: Dec 25 1999
 * This library is free.  You can redistribute it and/or modify it.
 */

function Utf8ArrayToStr(array) {
    var out, i, len, c;
    var char2, char3;

    out = "";
    len = array.length;
    i = 0;
    while(i < len) {
    c = array[i++];
    switch(c >> 4)
    { 
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
        // 0xxxxxxx
        out += String.fromCharCode(c);
        break;
      case 12: case 13:
        // 110x xxxx   10xx xxxx
        char2 = array[i++];
        out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
        break;
      case 14:
        // 1110 xxxx  10xx xxxx  10xx xxxx
        char2 = array[i++];
        char3 = array[i++];
        out += String.fromCharCode(((c & 0x0F) << 12) |
                       ((char2 & 0x3F) << 6) |
                       ((char3 & 0x3F) << 0));
        break;
    }
    }

    return out;
}

ค่อนข้างสะอาดกว่าโซลูชันอื่น ๆ เนื่องจากไม่ใช้แฮ็กใด ๆ หรือขึ้นอยู่กับฟังก์ชั่น Browser JS เช่นใช้งานได้ในสภาพแวดล้อม JS อื่น ๆ

ตรวจสอบการสาธิต JSFiddle

ดูคำถามที่เกี่ยวข้องได้ที่นี่และที่นี่


6
นี่ดูเหมือนช้านะ แต่เพียงตัวอย่างเดียวในจักรวาลที่ฉันพบว่าใช้งานได้ การค้นหาที่ดี + การนำไปใช้!
Redsandro

6
ฉันไม่เข้าใจว่าทำไมถึงไม่มีการโหวตเพิ่มขึ้น ดูเหมือนว่ามีเหตุผลอย่างชัดเจนที่จะเหวี่ยงผ่านข้อตกลง UTF-8 สำหรับตัวอย่างขนาดเล็ก Async Blob + Filereader ใช้งานได้ดีกับข้อความขนาดใหญ่ตามที่คนอื่นระบุ
DanHorner

2
คำถามคือจะทำอย่างไรโดยไม่ต้องต่อสตริง
Jack Wester

5
ใช้งานได้ดียกเว้นว่าจะไม่จัดการลำดับ 4+ ไบต์เช่นfromUTF8Array([240,159,154,133])กลายเป็นว่างเปล่า (ในขณะที่fromUTF8Array([226,152,131])→"☃")
unhammer

1
เหตุใดกรณี 8, 9, 10 และ 11 จึงถูกยกเว้น เหตุผลใดเป็นพิเศษ? และกรณีที่ 15 เป็นไปได้ด้วยใช่ไหม? 15 (1111) จะแสดงว่ามีการใช้ 4 ไบต์ใช่หรือไม่?
RaR

31

นี่คือสิ่งที่ฉันใช้:

var str = String.fromCharCode.apply(null, uint8Arr);

7
จากเอกสารดูเหมือนจะไม่ถอดรหัส UTF8
Albert

29
สิ่งนี้จะส่งผลRangeErrorต่อข้อความที่ใหญ่กว่า "เกินขนาดกองการโทรสูงสุด"
Redsandro

1
หากคุณมีการแปลง Uint8Arrays ขนาดใหญ่เพื่อสตริงไบนารีและจะได้รับ RangeError ดูฟังก์ชัน Uint8ToString จากstackoverflow.com/a/12713326/471341
yonran

IE 11 จะพ่นSCRIPT28: Out of stack spaceเมื่อฉันป้อนมัน 300 + k ตัวอักษรหรือRangeErrorสำหรับ Chrome 39 Firefox 33 ก็โอเค 100 + k ทำงานได้ดีกับทั้งสาม
Sheepy

นี้ไม่ได้ผลิตผลลัพธ์ที่ถูกต้องจากตัวอักษรตัวอย่าง Unicode ในen.wikipedia.org/wiki/UTF-8 เช่น String.fromCharCode.apply (null, new Uint8Array ([0xc2, 0xa2])) ไม่สร้าง¢
Vincent Scheib

16

พบในหนึ่งในแอปพลิเคชันตัวอย่างของ Chrome แม้ว่าจะมีไว้สำหรับกลุ่มข้อมูลขนาดใหญ่ที่คุณสามารถใช้การแปลงแบบอะซิงโครนัสได้

/**
 * Converts an array buffer to a string
 *
 * @private
 * @param {ArrayBuffer} buf The buffer to convert
 * @param {Function} callback The function to call when conversion is complete
 */
function _arrayBufferToString(buf, callback) {
  var bb = new Blob([new Uint8Array(buf)]);
  var f = new FileReader();
  f.onload = function(e) {
    callback(e.target.result);
  };
  f.readAsText(bb);
}

2
ดังที่คุณกล่าวไว้สิ่งนี้จะทำงานได้แย่มากเว้นแต่บัฟเฟอร์ที่จะแปลงนั้นใหญ่มาก UTF-8 แบบซิงโครนัสเพื่อแปลง wchar ของสตริงธรรมดา (พูด 10-40 ไบต์) ที่ใช้งานกล่าวว่า V8 ควรน้อยกว่าหนึ่งไมโครวินาทีในขณะที่ฉันเดาว่ารหัสของคุณต้องใช้หลายร้อยครั้ง ขอบคุณเหมือนกัน
Jack Wester

15

อินสแตนซ์ In Node " Bufferยังเป็นUint8Arrayอินสแตนซ์ " ดังนั้นจึงbuf.toString()ใช้ได้ในกรณีนี้


ใช้งานได้ดีสำหรับฉัน และง่ายมาก! แต่ที่จริงแล้วUint8Arrayมีวิธี toString ()
ดูม

เรียบง่ายและสง่างามไม่ทราบBufferก็คือ Uint8Array ขอบคุณ!
LeOn - Han Li

1
@doom ในฝั่งเบราว์เซอร์ Uint8Array.toString () จะไม่รวบรวมสตริง utf-8 มันจะแสดงรายการค่าตัวเลขในอาร์เรย์ ดังนั้นหากสิ่งที่คุณมีคือ Uint8Array จากแหล่งอื่นที่ไม่ได้เป็น Buffer ด้วยคุณจะต้องสร้างขึ้นมาเพื่อทำเวทมนตร์:Buffer.from(uint8array).toString('utf-8')
Joachim Lous

12

วิธีการแก้ปัญหาที่อัลเบิร์ตมอบให้ใช้งานได้ดีตราบเท่าที่มีการเรียกใช้ฟังก์ชันที่ให้มาไม่บ่อยนักและใช้สำหรับอาร์เรย์ที่มีขนาดพอประมาณเท่านั้นมิฉะนั้นจะไม่มีประสิทธิภาพอย่างมาก นี่คือโซลูชัน JavaScript วานิลลาขั้นสูงที่ใช้ได้กับทั้งโหนดและเบราว์เซอร์และมีข้อดีดังต่อไปนี้:

•ทำงานได้อย่างมีประสิทธิภาพสำหรับขนาดอาร์เรย์ octet ทั้งหมด

•ไม่สร้างสตริงการโยนทิ้งกลาง

•รองรับอักขระ 4 ไบต์ในเอ็นจิ้น JS สมัยใหม่ (มิฉะนั้นจะแทนที่ "?")

var utf8ArrayToStr = (function () {
    var charCache = new Array(128);  // Preallocate the cache for the common single byte chars
    var charFromCodePt = String.fromCodePoint || String.fromCharCode;
    var result = [];

    return function (array) {
        var codePt, byte1;
        var buffLen = array.length;

        result.length = 0;

        for (var i = 0; i < buffLen;) {
            byte1 = array[i++];

            if (byte1 <= 0x7F) {
                codePt = byte1;
            } else if (byte1 <= 0xDF) {
                codePt = ((byte1 & 0x1F) << 6) | (array[i++] & 0x3F);
            } else if (byte1 <= 0xEF) {
                codePt = ((byte1 & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else if (String.fromCodePoint) {
                codePt = ((byte1 & 0x07) << 18) | ((array[i++] & 0x3F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else {
                codePt = 63;    // Cannot convert four byte code points, so use "?" instead
                i += 3;
            }

            result.push(charCache[codePt] || (charCache[codePt] = charFromCodePt(codePt)));
        }

        return result.join('');
    };
})();

2
ทางออกที่ดีที่สุดที่นี่เนื่องจากจัดการกับอักขระ 4 ไบต์ (เช่นอิโมจิ) ขอบคุณ!
fiffy

1
และสิ่งที่ผกผันของสิ่งนี้คืออะไร?
simbo1905

6

ทำในสิ่งที่ @Sudhir กล่าวจากนั้นเพื่อให้ String ออกจากรายการตัวเลขที่คั่นด้วยจุลภาคให้ใช้:

for (var i=0; i<unitArr.byteLength; i++) {
            myString += String.fromCharCode(unitArr[i])
        }

สิ่งนี้จะให้สตริงที่คุณต้องการหากยังเกี่ยวข้อง


ขออภัยไม่ได้สังเกตเห็นประโยคสุดท้ายที่คุณบอกว่าไม่ต้องการเพิ่มทีละอักขระ หวังว่านี่จะช่วยคนอื่น ๆ ที่ไม่มีปัญหากับการใช้งาน CPU ได้
shuki

14
สิ่งนี้ไม่ได้ทำการถอดรหัส UTF8
Albert

ยิ่งสั้น: String.fromCharCode.apply(null, unitArr);. ดังที่ได้กล่าวไว้มันไม่ได้จัดการกับการเข้ารหัส UTF8 แต่บางครั้งก็ง่ายพอหากคุณต้องการเพียงการสนับสนุน ASCII แต่ไม่สามารถเข้าถึง TextEncoder / TextDecoder ได้
Ravenstine

คำตอบกล่าวถึง @Sudhir แต่ฉันค้นหาหน้าเว็บและพบคำตอบดังกล่าว ดังนั้นจะเป็นการดีกว่าที่จะแทรกสิ่งที่เขาพูดไว้
Joakim

สิ่งนี้จะมีประสิทธิภาพที่แย่มากในสายที่ยาวกว่า อย่าใช้ตัวดำเนินการ + กับสตริง
สูงสุด

3

หากคุณไม่สามารถใช้TextDecoder API ได้เนื่องจากไม่รองรับ IE :

  1. คุณสามารถใช้โพลีฟิลล์ FastestSm maximumTextEncoderDecoder ที่แนะนำโดยเว็บไซต์Mozilla Developer Network ;
  2. คุณสามารถใช้ฟังก์ชันนี้ได้ที่เว็บไซต์ MDN :

function utf8ArrayToString(aBytes) {
    var sView = "";
    
    for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
        nPart = aBytes[nIdx];
        
        sView += String.fromCharCode(
            nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
                /* (nPart - 252 << 30) may be not so safe in ECMAScript! So...: */
                (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
                (nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
                (nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
                (nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
                (nPart - 192 << 6) + aBytes[++nIdx] - 128
            : /* nPart < 127 ? */ /* one byte */
                nPart
        );
    }
    
    return sView;
}

let str = utf8ArrayToString([50,72,226,130,130,32,43,32,79,226,130,130,32,226,135,140,32,50,72,226,130,130,79]);

// Must show 2H₂ + O₂ ⇌ 2H₂O
console.log(str);


2

ลองใช้ฟังก์ชันเหล่านี้

var JsonToArray = function(json)
{
    var str = JSON.stringify(json, null, 0);
    var ret = new Uint8Array(str.length);
    for (var i = 0; i < str.length; i++) {
        ret[i] = str.charCodeAt(i);
    }
    return ret
};

var binArrayToJson = function(binArray)
{
    var str = "";
    for (var i = 0; i < binArray.length; i++) {
        str += String.fromCharCode(parseInt(binArray[i]));
    }
    return JSON.parse(str)
}

แหล่งที่มา: https://gist.github.com/tomfa/706d10fed78c497731acความรุ่งโรจน์ถึง Tomfa


2

ฉันรู้สึกผิดหวังที่เห็นว่าผู้คนไม่ได้แสดงวิธีการไปทั้งสองทางหรือแสดงให้เห็นว่าสิ่งต่าง ๆ ใช้งานได้กับสตริง UTF8 ที่ไม่สำคัญ ฉันพบโพสต์บน codereview.stackexchange.comซึ่งมีโค้ดบางอย่างที่ใช้งานได้ดี ฉันใช้มันเพื่อเปลี่ยนอักษรรูนโบราณให้เป็นไบต์เพื่อทดสอบคริปโปในไบต์จากนั้นแปลงสิ่งต่างๆกลับเป็นสตริง รหัสที่ทำงานอยู่บน GitHub ที่นี่ ฉันเปลี่ยนชื่อวิธีการเพื่อความชัดเจน:

// https://codereview.stackexchange.com/a/3589/75693
function bytesToSring(bytes) {
    var chars = [];
    for(var i = 0, n = bytes.length; i < n;) {
        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
    }
    return String.fromCharCode.apply(null, chars);
}

// https://codereview.stackexchange.com/a/3589/75693
function stringToBytes(str) {
    var bytes = [];
    for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
    }
    return bytes;
}

การทดสอบหน่วยใช้สตริง UTF-8 นี้:

    // http://kermitproject.org/utf8.html
    // From the Anglo-Saxon Rune Poem (Rune version) 
    const secretUtf8 = `ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ
ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ
ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬`;

โปรดทราบว่าความยาวสตริงคือ 117 อักขระ แต่ความยาวไบต์เมื่อเข้ารหัสคือ 234

ถ้าฉันยกเลิกการใส่เครื่องหมายในบรรทัด console.log ฉันจะเห็นว่าสตริงที่ถอดรหัสเป็นสตริงเดียวกันกับที่เข้ารหัส (โดยไบต์ที่ส่งผ่านอัลกอริธึมการแบ่งปันความลับของ Shamir!):

การทดสอบหน่วยที่สาธิตการเข้ารหัสและถอดรหัส


String.fromCharCode.apply(null, chars)จะผิดพลาดหากcharsใหญ่เกินไป
Marc J. Schmidt

เป็นทุกที่หรือแค่บางเบราว์เซอร์และมีการบันทึกไว้หรือไม่
simbo1905

เช่นที่นี่developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… But beware: by using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (that is, more than tens of thousands of arguments) varies across engines. (The JavaScriptCore engine has hard-coded argument limit of 65536.
Marc J. Schmidt

ขอบคุณ ในกรณีของฉันฉันกำลังทำการเข้ารหัสลับบนสายอักขระขนาดเล็กดังนั้นจึงไม่ใช่ปัญหา คุณมีวิธีแก้ไขสตริงยาวหรือไม่? :-)
simbo1905

1
วิธีแก้ปัญหาคือการแบทช์เป็น 64k ตัวอักษร
Marc J. Schmidt

1

ใน NodeJS เรามีบัฟเฟอร์ให้ใช้งานและการแปลงสตริงด้วยมันก็ง่ายมาก ดีกว่าง่ายต่อการแปลง Uint8Array เป็นบัฟเฟอร์ ลองใช้รหัสนี้มันใช้ได้สำหรับฉันใน Node สำหรับการแปลงใด ๆ ที่เกี่ยวข้องกับ Uint8Arrays:

let str = Buffer.from(uint8arr.buffer).toString();

เราแค่แยก ArrayBuffer ออกจาก Uint8Array แล้วแปลงเป็น NodeJS Buffer ที่เหมาะสม จากนั้นเราจะแปลง Buffer เป็นสตริง (คุณสามารถโยนการเข้ารหัส hex หรือ base64 ได้หากต้องการ)

หากเราต้องการแปลงกลับเป็น Uint8Array จากสตริงเราจะทำสิ่งนี้:

let uint8arr = new Uint8Array(Buffer.from(str));

โปรดทราบว่าหากคุณประกาศการเข้ารหัสเช่น base64 เมื่อแปลงเป็นสตริงคุณจะต้องใช้Buffer.from(str, "base64")ถ้าคุณใช้ base64 หรือการเข้ารหัสอื่น ๆ ที่คุณใช้

สิ่งนี้จะไม่ทำงานในเบราว์เซอร์ที่ไม่มีโมดูล! NodeJS Buffers ไม่มีอยู่ในเบราว์เซอร์ดังนั้นวิธีนี้จะไม่ได้ผลเว้นแต่คุณจะเพิ่มฟังก์ชัน Buffer ให้กับเบราว์เซอร์ มันค่อนข้างง่ายที่จะทำเพียงแค่ใช้โมดูลแบบนี้ซึ่งทั้งเล็กและเร็ว!


0
class UTF8{
static encode(str:string){return new UTF8().encode(str)}
static decode(data:Uint8Array){return new UTF8().decode(data)}

private EOF_byte:number = -1;
private EOF_code_point:number = -1;
private encoderError(code_point) {
    console.error("UTF8 encoderError",code_point)
}
private decoderError(fatal, opt_code_point?):number {
    if (fatal) console.error("UTF8 decoderError",opt_code_point)
    return opt_code_point || 0xFFFD;
}
private inRange(a:number, min:number, max:number) {
    return min <= a && a <= max;
}
private div(n:number, d:number) {
    return Math.floor(n / d);
}
private stringToCodePoints(string:string) {
    /** @type {Array.<number>} */
    let cps = [];
    // Based on http://www.w3.org/TR/WebIDL/#idl-DOMString
    let i = 0, n = string.length;
    while (i < string.length) {
        let c = string.charCodeAt(i);
        if (!this.inRange(c, 0xD800, 0xDFFF)) {
            cps.push(c);
        } else if (this.inRange(c, 0xDC00, 0xDFFF)) {
            cps.push(0xFFFD);
        } else { // (inRange(c, 0xD800, 0xDBFF))
            if (i == n - 1) {
                cps.push(0xFFFD);
            } else {
                let d = string.charCodeAt(i + 1);
                if (this.inRange(d, 0xDC00, 0xDFFF)) {
                    let a = c & 0x3FF;
                    let b = d & 0x3FF;
                    i += 1;
                    cps.push(0x10000 + (a << 10) + b);
                } else {
                    cps.push(0xFFFD);
                }
            }
        }
        i += 1;
    }
    return cps;
}

private encode(str:string):Uint8Array {
    let pos:number = 0;
    let codePoints = this.stringToCodePoints(str);
    let outputBytes = [];

    while (codePoints.length > pos) {
        let code_point:number = codePoints[pos++];

        if (this.inRange(code_point, 0xD800, 0xDFFF)) {
            this.encoderError(code_point);
        }
        else if (this.inRange(code_point, 0x0000, 0x007f)) {
            outputBytes.push(code_point);
        } else {
            let count = 0, offset = 0;
            if (this.inRange(code_point, 0x0080, 0x07FF)) {
                count = 1;
                offset = 0xC0;
            } else if (this.inRange(code_point, 0x0800, 0xFFFF)) {
                count = 2;
                offset = 0xE0;
            } else if (this.inRange(code_point, 0x10000, 0x10FFFF)) {
                count = 3;
                offset = 0xF0;
            }

            outputBytes.push(this.div(code_point, Math.pow(64, count)) + offset);

            while (count > 0) {
                let temp = this.div(code_point, Math.pow(64, count - 1));
                outputBytes.push(0x80 + (temp % 64));
                count -= 1;
            }
        }
    }
    return new Uint8Array(outputBytes);
}

private decode(data:Uint8Array):string {
    let fatal:boolean = false;
    let pos:number = 0;
    let result:string = "";
    let code_point:number;
    let utf8_code_point = 0;
    let utf8_bytes_needed = 0;
    let utf8_bytes_seen = 0;
    let utf8_lower_boundary = 0;

    while (data.length > pos) {
        let _byte = data[pos++];

        if (_byte == this.EOF_byte) {
            if (utf8_bytes_needed != 0) {
                code_point = this.decoderError(fatal);
            } else {
                code_point = this.EOF_code_point;
            }
        } else {
            if (utf8_bytes_needed == 0) {
                if (this.inRange(_byte, 0x00, 0x7F)) {
                    code_point = _byte;
                } else {
                    if (this.inRange(_byte, 0xC2, 0xDF)) {
                        utf8_bytes_needed = 1;
                        utf8_lower_boundary = 0x80;
                        utf8_code_point = _byte - 0xC0;
                    } else if (this.inRange(_byte, 0xE0, 0xEF)) {
                        utf8_bytes_needed = 2;
                        utf8_lower_boundary = 0x800;
                        utf8_code_point = _byte - 0xE0;
                    } else if (this.inRange(_byte, 0xF0, 0xF4)) {
                        utf8_bytes_needed = 3;
                        utf8_lower_boundary = 0x10000;
                        utf8_code_point = _byte - 0xF0;
                    } else {
                        this.decoderError(fatal);
                    }
                    utf8_code_point = utf8_code_point * Math.pow(64, utf8_bytes_needed);
                    code_point = null;
                }
            } else if (!this.inRange(_byte, 0x80, 0xBF)) {
                utf8_code_point = 0;
                utf8_bytes_needed = 0;
                utf8_bytes_seen = 0;
                utf8_lower_boundary = 0;
                pos--;
                code_point = this.decoderError(fatal, _byte);
            } else {
                utf8_bytes_seen += 1;
                utf8_code_point = utf8_code_point + (_byte - 0x80) * Math.pow(64, utf8_bytes_needed - utf8_bytes_seen);

                if (utf8_bytes_seen !== utf8_bytes_needed) {
                    code_point = null;
                } else {
                    let cp = utf8_code_point;
                    let lower_boundary = utf8_lower_boundary;
                    utf8_code_point = 0;
                    utf8_bytes_needed = 0;
                    utf8_bytes_seen = 0;
                    utf8_lower_boundary = 0;
                    if (this.inRange(cp, lower_boundary, 0x10FFFF) && !this.inRange(cp, 0xD800, 0xDFFF)) {
                        code_point = cp;
                    } else {
                        code_point = this.decoderError(fatal, _byte);
                    }
                }

            }
        }
        //Decode string
        if (code_point !== null && code_point !== this.EOF_code_point) {
            if (code_point <= 0xFFFF) {
                if (code_point > 0)result += String.fromCharCode(code_point);
            } else {
                code_point -= 0x10000;
                result += String.fromCharCode(0xD800 + ((code_point >> 10) & 0x3ff));
                result += String.fromCharCode(0xDC00 + (code_point & 0x3ff));
            }
        }
    }
    return result;
}

`


เพิ่มคำอธิบายเพื่อตอบ @terran
Rohit Poudel

-3

ฉันกำลังใช้ข้อมูลโค้ด typescript นี้:

function UInt8ArrayToString(uInt8Array: Uint8Array): string
{
    var s: string = "[";
    for(var i: number = 0; i < uInt8Array.byteLength; i++)
    {
        if( i > 0 )
            s += ", ";
        s += uInt8Array[i];
    }
    s += "]";
    return s;
}

ลบคำอธิบายประกอบประเภทหากคุณต้องการเวอร์ชัน JavaScript หวังว่านี่จะช่วยได้!


3
OP ขอให้ไม่เพิ่มทีละอักขระ นอกจากนี้เขาไม่ต้องการแสดงเป็นสตริงแทนรายการ แต่เป็นเพียงสตริง นอกจากนี้ยังไม่แปลงอักขระเป็นสตริง แต่แสดงจำนวน
Albert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.