Eu tenho uma string de javascript que tem cerca de 500 K quando enviada do servidor em UTF-8. Como posso saber seu tamanho em JavaScript?
Eu sei que JavaScript usa UCS-2, então isso significa 2 bytes por caractere. No entanto, isso depende da implementação do JavaScript? Ou na codificação da página ou talvez no tipo de conteúdo?
javascript
string
size
byte
Paul Biggar
fonte
fonte
Respostas:
String
os valores não são dependentes da implementação, de acordo com a Especificação ECMA-262 3ª Edição , cada caractere representa uma única unidade de 16 bits de texto UTF-16 :fonte
Esta função retornará o tamanho de byte de qualquer string UTF-8 que você passar para ela.
function byteCount(s) { return encodeURI(s).split(/%..|./).length - 1; }
Fonte
Os mecanismos JavaScript são gratuitos para usar o UCS-2 ou UTF-16 internamente. A maioria dos mecanismos que conheço usa UTF-16, mas seja qual for a escolha que eles fizeram, é apenas um detalhe de implementação que não afetará as características da linguagem.
A própria linguagem ECMAScript / JavaScript, no entanto, expõe caracteres de acordo com UCS-2, não UTF-16.
Fonte
fonte
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)
lugar. Seu snippet falha para strings que codificam para "% uXXXX".Se você estiver usando node.js, há uma solução mais simples usando buffers :
function getBinarySize(string) { return Buffer.byteLength(string, 'utf8'); }
Existe uma lib npm para isso: https://www.npmjs.org/package/utf8-binary-cutter (do seu fielmente)
fonte
Você pode usar o Blob para obter o tamanho da string em bytes.
Exemplos:
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) );
fonte
Buffer.from('😂').length
Experimente esta combinação usando a função unescape js:
const byteAmount = unescape(encodeURIComponent(yourString)).length
Exemplo de processo de codificação completa:
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
fonte
unescape
função JavaScript está obsoleta e não deve ser usada para decodificar Uniform Resource Identifiers (URI). Fonteunescape
não é usado, para decodificar URIs. É usado para converter%xx
sequências em caracteres únicos. O AsencodeURIComponent
codifica uma string como UTF-8, representando codeunits como seu caractere ASCII correspondente ou como uma%xx
sequência, chamando osunescape(encodeURIComponent(...))
resultados em uma string binária contendo a representação UTF-8 da string original. Chamar.length
corretamente fornece o tamanho em bytes da string codificada como UTF-8.un
)escape
está obsoleto desde 1999, mas ainda está disponível em todos os navegadores ... - Dito isso, há um bom motivo para ele. Basicamente, não há maneira de usá-los corretamente (exceto para en- / decoding UTF8 em combinação comen
- /decodeURI
(Component
) - ou pelo menos não conheço nenhum outro aplicativo útil para (un
)escape
). E hoje existem alternativas melhores para codificar / decodificar UTF8 (TextEncoder
, etc.)Observe que se você está direcionando o node.js, pode usar
Buffer.from(string).length
:var str = "\u2620"; // => "☠" str.length; // => 1 (character) Buffer.from(str).length // => 3 (bytes)
fonte
Estas são as 3 maneiras que eu uso:
TextEncoder
new TextEncoder().encode("myString").length
Blob
new Blob(["myString"]).size
Buffer
Buffer.byteLength("myString", 'utf8')
fonte
TextEncoder
opção é mais de 6 vezes mais rápida: i.ibb.co/QkfsJQN/Screenshot-from-2020-12-20-16-29-27.pngUTF-8 codifica caracteres usando 1 a 4 bytes por ponto de código. Como o CMS apontou na resposta aceita, o JavaScript armazenará cada caractere internamente usando 16 bits (2 bytes).
Se você analisar cada caractere na string por meio de um loop e contar o número de bytes usados por ponto de código e, em seguida, multiplicar a contagem total por 2, deverá ter o uso de memória JavaScript em bytes para essa string codificada em UTF-8. Talvez algo assim:
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; }
Exemplos:
getStringMemorySize( 'I' ); // 2 getStringMemorySize( '❤' ); // 4 getStringMemorySize( '𠀰' ); // 8 getStringMemorySize( 'I❤𠀰' ); // 14
fonte
O tamanho de uma string JavaScript é
Pré-ES6
Sempre 2 bytes por caractere. UTF-16 não é permitido porque a especificação diz "os valores devem ser inteiros sem sinal de 16 bits". Como as strings UTF-16 podem usar caracteres de 3 ou 4 bytes, isso violaria o requisito de 2 bytes. Crucialmente, enquanto UTF-16 não pode ser totalmente suportado, o padrão requer que os dois caracteres de byte usados sejam caracteres UTF-16 válidos. Em outras palavras, as sequências JavaScript Pré-ES6 suportam um subconjunto de caracteres UTF-16.
ES6 e posterior
2 bytes por caractere ou 5 ou mais bytes por caractere. Os tamanhos adicionais entram em jogo porque o ES6 (ECMAScript 6) adiciona suporte para escapes de ponto de código Unicode . O uso de um escape Unicode tem a seguinte aparência: \ u {1D306}
Notas práticas
Isso não se relaciona à implementação interna de um motor específico. Por exemplo, alguns mecanismos usam estruturas de dados e bibliotecas com suporte total a UTF-16, mas o que eles fornecem externamente não precisa ser suporte total a UTF-16. Além disso, um motor pode fornecer suporte UTF-16 externo, mas não é obrigado a fazê-lo.
Para ES6, os caracteres praticamente falando nunca terão mais de 5 bytes de comprimento (2 bytes para o ponto de escape + 3 bytes para o ponto de código Unicode) porque a versão mais recente do Unicode tem apenas 136.755 caracteres possíveis, que se encaixam facilmente em 3 bytes. No entanto, isso não é tecnicamente limitado pelo padrão, portanto, em princípio, um único caractere poderia usar, digamos, 4 bytes para o ponto de código e 6 bytes no total.
A maioria dos exemplos de código aqui para calcular o tamanho do byte não parecem levar em conta os escapes de ponto de código ES6 Unicode, portanto, os resultados podem estar incorretos em alguns casos.
fonte
Buffer.from('test').length
eBuffer.byteLength('test')
igual a 4 (em Node) enew Blob(['test']).size
também é igual a 4?'\u{1F600}'.length===2
,'\u{1F600}'==='\uD83D\uDE00'
,'\u{1F600}'==='😀'
)Um único elemento em uma String JavaScript é considerado uma única unidade de código UTF-16. Ou seja, os caracteres Strings são armazenados em 16 bits (1 unidade de código) e 16 bits é igual a 2 bytes (8 bits = 1 byte).
O
charCodeAt()
método pode ser usado para retornar um número inteiro entre 0 e 65535 que representa a unidade de código UTF-16 no índice fornecido.O
codePointAt()
pode ser usado para retornar o valor de ponto de código inteiro para caracteres Unicode, por exemplo, UTF-32.Quando um caractere UTF-16 não pode ser representado em uma única unidade de código de 16 bits, ele terá um par substituto e, portanto, usará duas unidades de código (2 x 16 bits = 4 bytes)
Consulte codificações Unicode para codificações diferentes e seus intervalos de código.
fonte
A resposta de Lauri Oherd funciona bem para a maioria das strings vistas em estado selvagem, mas falhará se a string contiver caracteres solitários no intervalo do par substituto, 0xD800 a 0xDFFF. Por exemplo
byteCount(String.fromCharCode(55555)) // URIError: URI malformed
Esta função mais longa deve lidar com todas as strings:
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; }
Por exemplo
bytes(String.fromCharCode(55555)) // 3
Ele calculará corretamente o tamanho das strings que contêm pares substitutos:
bytes(String.fromCharCode(55555, 57000)) // 4 (not 6)
Os resultados podem ser comparados com a função integrada do Node
Buffer.byteLength
:Buffer.byteLength(String.fromCharCode(55555), 'utf8') // 3 Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8') // 4 (not 6)
fonte
Estou trabalhando com uma versão incorporada do V8 Engine. Eu testei uma única corda. Empurrando cada etapa 1000 caracteres. UTF-8.
Primeiro teste com caractere "A" de byte único (8 bits, ANSI) (hex: 41). Segundo teste com caracteres de dois bytes (16 bits) "Ω" (hex: CE A9) e o terceiro teste com caracteres de três bytes (24 bits) "☺" (hex: E2 98 BA).
Em todos os três casos, o dispositivo imprime sem memória em 888.000 caracteres e usando ca. 26 348 kb na RAM.
Resultado: os caracteres não são armazenados dinamicamente. E não com apenas 16 bits. - Ok, talvez apenas para o meu caso (Dispositivo embutido de 128 MB de RAM, V8 Engine C ++ / QT) - A codificação de caracteres não tem nada a ver com o tamanho da memória RAM do mecanismo javascript. Por exemplo, encodingURI, etc. só é útil para transmissão e armazenamento de dados de alto nível.
Incorporados ou não, o fato é que os personagens não são armazenados apenas em 16 bits. Infelizmente não tenho resposta 100%, o que Javascript faz em área de baixo nível. Btw. Eu testei o mesmo (primeiro teste acima) com uma matriz de caracteres "A". Empurrou 1000 itens a cada etapa. (Exatamente o mesmo teste. Apenas substituiu a string por array) E o sistema fica sem memória (desejado) após 10 416 KB usando um comprimento de array de 1 337 000. Portanto, o mecanismo de javascript não é simplesmente restrito. É um pouco mais complexo.
fonte
Você pode tentar isto:
var b = str.match(/[^\x00-\xff]/g); return (str.length + (!b ? 0: b.length));
Funcionou para mim
fonte