Saya memiliki string javascript sekitar 500K saat dikirim dari server dalam UTF-8. Bagaimana cara mengetahui ukurannya di JavaScript?
Saya tahu bahwa JavaScript menggunakan UCS-2, jadi apakah itu berarti 2 byte per karakter. Namun, apakah itu bergantung pada implementasi JavaScript? Atau pada pengkodean halaman atau mungkin tipe konten?
javascript
string
size
byte
Paul Biggar
sumber
sumber
Jawaban:
String
Nilai tidak bergantung pada implementasi, menurut Spesifikasi ECMA-262 Edisi ke-3 , setiap karakter mewakili satu unit 16-bit teks UTF-16 :sumber
Fungsi ini akan mengembalikan ukuran byte dari setiap string UTF-8 yang Anda berikan padanya.
function byteCount(s) { return encodeURI(s).split(/%..|./).length - 1; }
Sumber
Mesin JavaScript bebas menggunakan UCS-2 atau UTF-16 secara internal. Sebagian besar mesin yang saya tahu menggunakan UTF-16, tetapi apa pun pilihan yang mereka buat, itu hanya detail implementasi yang tidak akan memengaruhi karakteristik bahasa.
Bahasa ECMAScript / JavaScript itu sendiri, bagaimanapun, memperlihatkan karakter sesuai dengan UCS-2, bukan UTF-16.
Sumber
sumber
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)
sebagai gantinya. Cuplikan Anda gagal untuk string yang dienkode menjadi "% uXXXX".Jika Anda menggunakan node.js, ada solusi yang lebih sederhana menggunakan buffer :
function getBinarySize(string) { return Buffer.byteLength(string, 'utf8'); }
Ada lib npm untuk itu: https://www.npmjs.org/package/utf8-binary-cutter (dari Anda dengan setia)
sumber
Anda dapat menggunakan Blob untuk mendapatkan ukuran string dalam byte.
Contoh:
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) );
sumber
Buffer.from('😂').length
Coba kombinasi ini dengan menggunakan fungsi unescape js:
const byteAmount = unescape(encodeURIComponent(yourString)).length
Contoh proses encode penuh:
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
sumber
unescape
JavaScript tidak digunakan lagi dan tidak boleh digunakan untuk mendekode Uniform Resource Identifiers (URI). Sumberunescape
tidak digunakan, untuk memecahkan kode URI. Ini digunakan untuk mengubah%xx
urutan menjadi karakter tunggal. SaatencodeURIComponent
mengenkode string sebagai UTF-8, mewakili unit kode baik sebagai karakter ASCII yang sesuai atau sebagai%xx
urutan, memanggilunescape(encodeURIComponent(...))
hasil dalam string biner yang berisi representasi UTF-8 dari string asli. Memanggil.length
dengan benar memberikan ukuran dalam byte dari string yang dikodekan sebagai UTF-8.un
)escape
tidak digunakan lagi sejak 1999 tetapi masih tersedia di setiap browser ... - Artinya, ada alasan bagus untuk menghentikannya. Pada dasarnya tidak ada cara, untuk menggunakannya dengan benar (kecuali untuk en- / decoding UTF8 dalam kombinasi denganen
- /decodeURI
(Component
) - atau setidaknya saya tidak tahu aplikasi lain yang berguna untuk (un
)escape
). Dan hari ini ada alternatif yang lebih baik untuk menyandikan / mendekode UTF8 (TextEncoder
, dll.)Perhatikan bahwa jika Anda menargetkan node.js, Anda dapat menggunakan
Buffer.from(string).length
:var str = "\u2620"; // => "☠" str.length; // => 1 (character) Buffer.from(str).length // => 3 (bytes)
sumber
UTF-8 mengkodekan karakter menggunakan 1 hingga 4 byte per titik kode. Seperti yang ditunjukkan CMS dalam jawaban yang diterima, JavaScript akan menyimpan setiap karakter secara internal menggunakan 16 bit (2 byte).
Jika Anda mengurai setiap karakter dalam string melalui loop dan menghitung jumlah byte yang digunakan per titik kode, lalu mengalikan jumlah total dengan 2, Anda harus memiliki penggunaan memori JavaScript dalam byte untuk string berenkode UTF-8 tersebut. Mungkin sesuatu seperti ini:
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; }
Contoh:
getStringMemorySize( 'I' ); // 2 getStringMemorySize( '❤' ); // 4 getStringMemorySize( '𠀰' ); // 8 getStringMemorySize( 'I❤𠀰' ); // 14
sumber
Ini adalah 3 cara saya menggunakan:
TextEncoder ()
(new TextEncoder().encode("myString")).length)
Gumpal
new Blob(["myString"]).size)
Penyangga
Buffer.byteLength("myString", 'utf8'))
sumber
Ukuran string JavaScript adalah
Pre-ES6
Selalu 2 byte per karakter. UTF-16 tidak diizinkan karena spesifikasi mengatakan "nilai harus berupa bilangan bulat 16-bit unsigned". Karena string UTF-16 dapat menggunakan 3 atau 4 karakter byte, itu akan melanggar persyaratan 2 byte. Yang terpenting, meskipun UTF-16 tidak dapat sepenuhnya didukung, standarnya mengharuskan dua karakter byte yang digunakan adalah karakter UTF-16 yang valid. Dengan kata lain, string JavaScript Pre-ES6 mendukung subset karakter UTF-16.
ES6 dan yang lebih baru
2 byte per karakter, atau 5 atau lebih byte per karakter. Ukuran tambahan mulai berlaku karena ES6 (ECMAScript 6) menambahkan dukungan untuk pelolosan titik kode Unicode . Menggunakan pelolosan unicode terlihat seperti ini: \ u {1D306}
Catatan praktis
Ini tidak terkait dengan implementasi internal mesin tertentu. Misalnya, beberapa mesin menggunakan struktur dan pustaka data dengan dukungan UTF-16 penuh, tetapi apa yang mereka sediakan secara eksternal tidak harus dukungan penuh UTF-16. Selain itu, mesin juga dapat memberikan dukungan UTF-16 eksternal tetapi tidak diwajibkan untuk melakukannya.
Untuk ES6, praktis berbicara karakter tidak akan pernah lebih dari 5 byte (2 byte untuk titik keluar + 3 byte untuk titik kode Unicode) karena versi terbaru Unicode hanya memiliki 136.755 karakter yang mungkin, yang dengan mudah dapat dimasukkan ke dalam 3 byte. Namun ini secara teknis tidak dibatasi oleh standar sehingga pada prinsipnya satu karakter dapat digunakan katakanlah, 4 byte untuk titik kode dan total 6 byte.
Sebagian besar contoh kode di sini untuk menghitung ukuran byte tampaknya tidak memperhitungkan pelolosan titik kode Unicode ES6, sehingga hasilnya mungkin salah dalam beberapa kasus.
sumber
Buffer.from('test').length
danBuffer.byteLength('test')
sama dengan 4 (dalam Node) dannew Blob(['test']).size
juga sama dengan 4?'\u{1F600}'.length===2
,'\u{1F600}'==='\uD83D\uDE00'
,'\u{1F600}'==='😀'
)Satu elemen dalam JavaScript String dianggap sebagai satu unit kode UTF-16. Artinya, karakter Strings disimpan dalam 16-bit (1 unit kode), dan 16-bit sama dengan 2 byte (8-bit = 1 byte).
Itu
charCodeAt()
metode dapat digunakan untuk mengembalikan integer antara 0 dan 65535 mewakili unit kode UTF-16 di indeks yang diberikan.Itu
codePointAt()
dapat digunakan untuk mengembalikan seluruh nilai titik kode untuk karakter Unicode, misalnya UTF-32.Ketika karakter UTF-16 tidak dapat direpresentasikan dalam satu unit kode 16-bit, itu akan memiliki pasangan pengganti dan oleh karena itu menggunakan dua unit kode (2 x 16-bit = 4 byte)
Lihat pengkodean Unicode untuk berbagai pengkodean dan rentang kodenya.
sumber
Jawaban dari Lauri Oherd berfungsi dengan baik untuk sebagian besar string yang terlihat di alam liar, tetapi akan gagal jika string berisi karakter tunggal dalam rentang pasangan pengganti, 0xD800 hingga 0xDFFF. Misalnya
byteCount(String.fromCharCode(55555)) // URIError: URI malformed
Fungsi yang lebih panjang ini harus menangani semua string:
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; }
Misalnya
bytes(String.fromCharCode(55555)) // 3
Ini akan menghitung dengan benar ukuran string yang berisi pasangan pengganti:
bytes(String.fromCharCode(55555, 57000)) // 4 (not 6)
Hasilnya dapat dibandingkan dengan fungsi bawaan Node
Buffer.byteLength
:Buffer.byteLength(String.fromCharCode(55555), 'utf8') // 3 Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8') // 4 (not 6)
sumber
Saya bekerja dengan versi tertanam dari Mesin V8. Saya telah menguji satu string. Mendorong setiap langkah 1000 karakter. UTF-8.
Tes pertama dengan byte tunggal (8bit, ANSI) Karakter "A" (hex: 41). Tes kedua dengan karakter dua byte (16bit) "Ω" (hex: CE A9) dan tes ketiga dengan karakter tiga byte (24bit) "☺" (hex: E2 98 BA).
Dalam ketiga kasus, perangkat mencetak keluar memori pada 888.000 karakter dan menggunakan ca. 26 348 kb dalam RAM.
Hasil: Karakter tidak disimpan secara dinamis. Dan tidak hanya dengan 16bit. - Ok, mungkin hanya untuk kasus saya (Perangkat RAM 128 MB yang Disematkan, V8 Engine C ++ / QT) - Pengkodean karakter tidak ada hubungannya dengan ukuran dalam ram mesin javascript. Misalnya encodingURI, dll. Hanya berguna untuk transmisi dan penyimpanan data tingkat tinggi.
Disematkan atau tidak, faktanya karakter tidak hanya disimpan dalam 16bit. Sayangnya saya tidak punya jawaban 100%, apa yang Javascript lakukan di area level rendah. Btw. Saya telah menguji yang sama (tes pertama di atas) dengan array karakter "A". Mendorong 1000 item setiap langkah. (Tes yang persis sama. Baru saja mengganti string ke array) Dan sistem mengeluarkan memori (diinginkan) setelah 10 416 KB menggunakan dan panjang array 1 337.000. Jadi, mesin javascript tidak mudah dibatasi. Ini lebih kompleks.
sumber
Anda dapat mencoba ini:
var b = str.match(/[^\x00-\xff]/g); return (str.length + (!b ? 0: b.length));
Itu berhasil untuk saya.
sumber