Uint8Array na ciąg w JavaScript

122

Mam pewne dane zakodowane w UTF-8, które znajdują się w szeregu elementów Uint8Array w JavaScript. Czy istnieje skuteczny sposób na zdekodowanie ich do zwykłego ciągu javascript (uważam, że JavaScript używa 16-bitowego Unicode)? Nie chcę dodawać jednego znaku na raz, ponieważ konkaternacja ciągów będzie obciążać procesor.

Jack Wester
źródło
Nie jestem pewien, czy to zadziała, ale używam u8array.toString()podczas odczytu plików z BrowserFS, które ujawniają obiekt Uint8Array podczas wywoływania fs.readFile.
jcubic
1
@jcubic for me, toStringon Uint8Arrayzwraca liczby oddzielone przecinkami, takie jak "91,50,48,49,57,45"(Chrome 79)
kolen

Odpowiedzi:

172

TextEncoderi TextDecoderze standardu Encoding , który jest wypełniany przez bibliotekę stringencoding , konwertuje między ciągami a ArrayBuffers:

var uint8array = new TextEncoder("utf-8").encode("¢");
var string = new TextDecoder("utf-8").decode(uint8array);
Vincent Scheib
źródło
40
Dla każdego, leniwe jak ja npm install text-encoding, var textEncoding = require('text-encoding'); var TextDecoder = textEncoding.TextDecoder;. Nie, dziękuję.
Evan Hu
16
uważaj na bibliotekę kodowania tekstu npm, analizator pakietów
webpack
3
Przeglądarki @VincentScheib usunęły obsługę wszystkich innych formatów z wyjątkiem utf-8. Więc TextEncoderargument jest niepotrzebny!
tripulse
1
nodejs.org/api/string_decoder.html z przykładu: const {StringDecoder} = require ('string_decoder'); const decoder = new StringDecoder ('utf8'); const cent = Buffer.from ([0xC2, 0xA2]); console.log (decoder.write (cent));
kurysta
4
Zwróć uwagę, że Node.js dodał TextEncoder/ TextDecoderAPI w wersji 11, więc nie ma potrzeby instalowania żadnych dodatkowych pakietów, jeśli celem jest tylko bieżąca wersja Node.
Loilo
42

To powinno działać:

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

/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <[email protected]>
 * 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;
}

Jest trochę czystszy jak inne rozwiązania, ponieważ nie używa żadnych hacków ani nie jest zależny od funkcji Browser JS, np. Działa również w innych środowiskach JS.

Sprawdź demo JSFiddle .

Zobacz także powiązane pytania: tutaj i tutaj

Albert
źródło
6
To wydaje się trochę powolne. Ale jedyny fragment we wszechświecie, który znalazłem, działa. Dobre znalezisko + adopcja!
Redsandro
6
Nie rozumiem, dlaczego nie ma więcej głosów za. Wydaje się niezwykle rozsądne, aby przejść przez konwencję UTF-8 dla małych fragmentów. Async Blob + Filereader działa świetnie w przypadku dużych tekstów, jak wskazali inni.
DanHorner
2
Pytanie brzmiało, jak to zrobić bez konkatenacji ciągów
Jack Wester
5
Działa świetnie, z wyjątkiem tego, że nie obsługuje sekwencji 4+ bajtów, np. fromUTF8Array([240,159,154,133])Okazuje się pusty (podczas fromUTF8Array([226,152,131])→"☃")
unhammer
1
Dlaczego przypadki 8, 9, 10 i 11 są wykluczone? Jakiś konkretny powód? A przypadek 15 też jest możliwy, prawda? 15 (1111) będzie oznaczać, że używane są 4 bajty, prawda?
RaR
31

Oto czego używam:

var str = String.fromCharCode.apply(null, uint8Arr);
dlchambers
źródło
7
Z dokumentu nie wydaje się, aby to dekodowało UTF8.
Albert
29
Spowoduje to dodanie RangeErrorwiększych tekstów. „Przekroczono maksymalny rozmiar stosu połączeń”
Redsandro
1
Jeśli konwertujesz duże Uint8Arrays na ciągi binarne i otrzymujesz RangeError, zobacz funkcję Uint8ToString ze stackoverflow.com/a/12713326/471341 .
yonran
IE 11 wyrzuca, SCRIPT28: Out of stack spacegdy podaję 300 + k znaków, lub RangeErrordla Chrome 39. Firefox 33 jest w porządku. 100 + k działa dobrze ze wszystkimi trzema.
Sheepy
To nie daje poprawnego wyniku z przykładowych znaków Unicode na en.wikipedia.org/wiki/UTF-8 . np. String.fromCharCode.apply (null, new Uint8Array ([0xc2, 0xa2])) nie daje ¢.
Vincent Scheib
16

Znajduje się w jednej z przykładowych aplikacji Chrome, chociaż jest to przeznaczone dla większych bloków danych, w przypadku których konwersja asynchroniczna nie przeszkadza.

/**
 * 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);
}
Will Scott
źródło
2
Jak powiedziałeś, działałoby to strasznie, gdyby bufor do konwersji nie był naprawdę naprawdę duży. Synchroniczna konwersja UTF-8 do wchar prostego ciągu (powiedzmy 10-40 bajtów) zaimplementowana w, powiedzmy, V8 powinna być znacznie krótsza niż mikrosekunda, podczas gdy przypuszczam, że twój kod wymagałby tego setki razy. Mimo wszystko dzięki.
Jack Wester
15

W Node „ Bufferinstancje są również Uint8Arrayinstancjami ”, więc buf.toString()działa w tym przypadku.

kpowz
źródło
U mnie działa świetnie. I takie proste! Ale w rzeczywistości Uint8Array ma metodę toString ().
doom
Prosty i elegancki, nie był Bufferrównież świadomy Uint8Array. Dzięki!
LeOn - Han Li
1
@doom Po stronie przeglądarki Uint8Array.toString () nie skompiluje ciągu utf-8, wyświetli wartości liczbowe w tablicy. Więc jeśli masz tablicę Uint8Array z innego źródła, która nie jest również buforem, będziesz musiał ją stworzyć, aby zrobić magię:Buffer.from(uint8array).toString('utf-8')
Joachim Lous
12

Rozwiązanie podane przez Alberta działa dobrze, o ile podana funkcja jest wywoływana rzadko i jest używana tylko dla tablic o niewielkich rozmiarach, w przeciwnym razie jest rażąco nieefektywna. Oto ulepszone rozwiązanie w języku waniliowym JavaScript, które działa zarówno w przypadku węzła, jak i przeglądarek, i ma następujące zalety:

• Działa wydajnie dla wszystkich rozmiarów tablic oktetów

• Nie generuje pośrednich łańcuchów jednorazowego użytku

• Obsługuje 4-bajtowe znaki w nowoczesnych silnikach JS (w przeciwnym razie zastępowane jest „?”)

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('');
    };
})();
Bob Arlof
źródło
2
Najlepsze rozwiązanie tutaj, ponieważ obsługuje również 4-bajtowe znaki (np. Emoji) Dziękuję!
fiffy
1
i co jest odwrotnością tego?
simbo1905
6

Zrób to, co powiedział @Sudhir, a następnie, aby uzyskać ciąg znaków z rozdzielonej przecinkami listy liczb, użyj:

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

To da ci żądany ciąg, jeśli nadal jest istotny

shuki
źródło
Przepraszamy, nie zauważyłem ostatniego zdania, w którym powiedziałeś, że nie chcesz dodawać jednego znaku na raz. Mam nadzieję, że pomoże to innym, którzy nie mają problemu z wykorzystaniem procesora.
shuki
14
To nie powoduje dekodowania UTF8.
Albert
Nawet krócej: String.fromCharCode.apply(null, unitArr);. Jak wspomniano, nie obsługuje kodowania UTF8, ale czasami jest to wystarczająco proste, jeśli potrzebujesz tylko obsługi ASCII, ale nie masz dostępu do TextEncoder / TextDecoder.
Ravenstine
Odpowiedź wspomina o @Sudhir, ale przeszukałem stronę i znalazłem teraz taką odpowiedź. Więc lepiej byłoby wpisać wszystko, co powiedział
Joakim
To będzie miało fatalną wydajność na dłuższych strunach. Nie używaj operatora + na łańcuchach.
Max
3

Jeśli nie możesz użyć interfejsu API TextDecoder, ponieważ nie jest on obsługiwany w przeglądarce IE :

  1. Możesz użyć wypełnienia FastestSmallestTextEncoderDecoder zalecanego przez witrynę Mozilla Developer Network ;
  2. Możesz skorzystać z tej funkcji również na stronie 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);

Rosberg Linhares
źródło
2

Wypróbuj te funkcje,

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

źródło: https://gist.github.com/tomfa/706d10fed78c497731ac , kudos to Tomfa

serdarsenay
źródło
2

Byłem sfrustrowany, widząc, że ludzie nie pokazują, jak postępować w obie strony, ani nie pokazują, że wszystko działa na żadnych trywialnych łańcuchach UTF8. Znalazłem post na codereview.stackexchange.com, który zawiera kod, który działa dobrze. Użyłem go, aby zamienić starożytne runy w bajty, przetestować trochę kripo na bajtach, a następnie przekształcić je z powrotem w ciąg. Działający kod jest na github tutaj . Zmieniłem nazwy metod dla przejrzystości:

// 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;
}

Test jednostkowy używa tego ciągu UTF-8:

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

Zwróć uwagę, że długość ciągu wynosi tylko 117 znaków, ale długość bajtu po zakodowaniu to 234.

Jeśli odkomentuję wiersze console.log, widzę, że dekodowany ciąg jest tym samym ciągiem, który został zakodowany (z bajtami przekazanymi przez tajny algorytm udostępniania Shamira!):

test jednostkowy, który demonstruje kodowanie i dekodowanie

simbo1905
źródło
String.fromCharCode.apply(null, chars)błąd, jeśli charsjest za duży.
Marc J. Schmidt
czy to jest wszędzie, czy tylko w niektórych przeglądarkach i czy jest w ogóle udokumentowane?
simbo1905
np. tutaj 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
dzięki. w moim przypadku robiłem kryptowalutę na małych ciągach, więc nie ma problemu. czy masz poprawkę na długie struny? :-)
simbo1905
rozwiązaniem jest wsadowanie 64k znaków.
Marc J. Schmidt
1

W NodeJS mamy dostępne bufory, a konwersja ciągów za ich pomocą jest naprawdę łatwa. Co więcej, łatwo jest przekonwertować Uint8Array na bufor. Wypróbuj ten kod, działał dla mnie w Node w zasadzie dla każdej konwersji związanej z Uint8Arrays:

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

Po prostu wyodrębniamy ArrayBuffer z Uint8Array, a następnie konwertujemy go na odpowiedni bufor NodeJS. Następnie konwertujemy Buffer na łańcuch (możesz wrzucić kodowanie hex lub base64, jeśli chcesz).

Jeśli chcemy przekonwertować z powrotem na Uint8Array z łańcucha, zrobimy to:

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

Pamiętaj, że jeśli zadeklarowałeś kodowanie takie jak base64 podczas konwersji na ciąg, musisz użyć, Buffer.from(str, "base64")jeśli użyłeś base64 lub innego używanego kodowania.

To nie zadziała w przeglądarce bez modułu! Bufory NodeJS po prostu nie istnieją w przeglądarce, więc ta metoda nie będzie działać, chyba że dodasz funkcję bufora do przeglądarki. To rzeczywiście bardzo łatwe do zrobienia, chociaż, wystarczy użyć modułu jak ten , który jest zarówno małe i szybko!

Arctic_Hen7
źródło
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
źródło
Dodaj opis do odpowiedzi. @terran
Rohit Poudel
-3

Używam tego fragmentu kodu 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;
}

Usuń adnotacje typu, jeśli potrzebujesz wersji JavaScript. Mam nadzieję że to pomoże!

Bernd Paradies
źródło
3
OP poprosił, aby nie dodawać po jednym znaku na raz. Nie chce też wyświetlać go jako łańcucha reprezentującego listę, ale raczej jako łańcuch. Ponadto nie konwertuje to znaków na łańcuch, ale wyświetla jego liczbę.
Albert