W moim kodzie JavaScript muszę utworzyć wiadomość do serwera w następującym formacie:
<size in bytes>CRLF
<data>CRLF
Przykład:
3
foo
Dane mogą zawierać znaki Unicode. Muszę je wysłać jako UTF-8.
Szukam najbardziej używanego w różnych przeglądarkach sposobu obliczenia długości ciągu w bajtach w JavaScript.
Próbowałem tak skomponować mój ładunek:
return unescape(encodeURIComponent(str)).length + "\n" + str + "\n"
Ale nie daje mi dokładnych wyników dla starszych przeglądarek (a może ciągów znaków w tych przeglądarkach w UTF-16?).
Jakieś wskazówki?
Aktualizacja:
Przykład: długość w bajtach łańcucha ЭЭХ! Naïve?
w UTF-8 wynosi 15 bajtów, ale niektóre przeglądarki zamiast tego zgłaszają 23 bajty.
javascript
unicode
Alexander Gladysh
źródło
źródło
Odpowiedzi:
Nie ma możliwości zrobienia tego natywnie w JavaScript.(Zobacz odpowiedź Riccardo Galli na nowoczesne podejście.)W celach informacyjnych lub w przypadku, gdy interfejsy API TextEncoder są nadal niedostępne .
Jeśli znasz kodowanie znaków, możesz to obliczyć samodzielnie.
encodeURIComponent
przyjmuje UTF-8 jako kodowanie znaków, więc jeśli potrzebujesz tego kodowania, możesz to zrobić,Powinno to działać ze względu na sposób, w jaki UTF-8 koduje sekwencje wielobajtowe. Pierwszy zakodowany bajt zawsze zaczyna się od wysokiego bitu zerowego dla sekwencji jednobajtowej lub bajtu, którego pierwsza cyfra szesnastkowa to C, D, E lub F.Drugi i kolejne bajty to te, których pierwsze dwa bity to 10 To są dodatkowe bajty, które chcesz policzyć w UTF-8.
Stół w Wikipedii czyni to bardziej przejrzystym
Jeśli zamiast tego chcesz zrozumieć kodowanie strony, możesz użyć tej sztuczki:
źródło
lengthInUtf8Bytes
Funkcja zwraca 5 dla znaków innych niż BMP, jakstr.length
dla tych zwraca 2. Napiszę zmodyfikowaną wersję tej funkcji do sekcji odpowiedzi.encodeURIComponent('🍀')
jest'%F0%9F%8D%80'
.Minęły lata i teraz możesz to zrobić natywnie
Zauważ, że nie jest jeszcze obsługiwany przez IE (lub Edge) (możesz do tego użyć polyfill ).
Dokumentacja MDN
Standardowe specyfikacje
źródło
TextEncode
obsługuje tylko utf-8 od Chrome 53.Oto znacznie szybsza wersja, która nie używa wyrażeń regularnych ani encodeURIComponent () :
Oto porównanie wydajności .
Po prostu oblicza długość w UTF8 każdego punktu kodowego Unicode zwróconego przez charCodeAt () (na podstawie opisów UTF8 w Wikipedii i znaków zastępczych UTF16).
Jest zgodny z RFC3629 (gdzie znaki UTF-8 mają co najwyżej 4 bajty).
źródło
Dla prostego kodowania UTF-8, z nieco lepszą kompatybilnością niż
TextEncoder
Blob załatwia sprawę. Nie będzie jednak działać w bardzo starych przeglądarkach.źródło
Ta funkcja zwróci rozmiar bajtu dowolnego przekazanego do niej ciągu znaków UTF-8.
Źródło
źródło
ユーザーコード
długość w bajtach wynosi zawsze 21, przetestowałem to na różnych narzędziach; bądźcie bardziej uprzejmi z komentarzami;)Kolejne bardzo proste podejście wykorzystujące
Buffer
(tylko dla NodeJS):źródło
Buffer.byteLength(string, 'utf8')
.Trochę mi zajęło znalezienie rozwiązania dla React Native, więc umieszczę je tutaj:
Najpierw zainstaluj
buffer
pakiet:Następnie użyj metody węzła:
źródło
Właściwie to odkryłem, co jest nie tak. Aby kod działał, strona
<head>
powinna mieć następujący tag:Lub, jak sugerowano w komentarzach, jeśli serwer wysyła
Content-Encoding
nagłówek HTTP , to również powinno działać.Wtedy wyniki z różnych przeglądarek są spójne.
Oto przykład:
Uwaga: Podejrzewam, że określenie dowolnego (dokładnego) kodowania rozwiązałoby problem z kodowaniem. To tylko zbieg okoliczności, że potrzebuję UTF-8.
źródło
unescape
Funkcja JavaScript nie powinien być używany do dekodowania Uniform Resource Identifier (URI).unescape
nigdy nie powinno być używane do dekodowania identyfikatorów URI. Jednak konwersja tekstu do UTF-8 działa dobrzeunescape(encodeURIComponent(...)).length
zawsze oblicza prawidłową długość z lub bezmeta http-equiv ... utf8
. Bez specyfikacji kodowania niektóre przeglądarki mogą po prostu mieć inny tekst (po zakodowaniu bajtów dokumentu do rzeczywistego tekstu HTML), którego długość obliczają. Można to łatwo sprawdzić, drukując nie tylko długość, ale także sam tekst.Oto niezależna i wydajna metoda zliczania bajtów łańcucha w formacie UTF-8.
Należy zauważyć, że metoda może zgłosić błąd, jeśli ciąg wejściowy ma nieprawidłowy format UCS-2
źródło
W NodeJS
Buffer.byteLength
jest to metoda specjalnie do tego celu:Zwróć uwagę, że domyślnie metoda zakłada, że ciąg jest w kodowaniu UTF-8. Jeśli wymagane jest inne kodowanie, przekaż je jako drugi argument.
źródło
strLengthInBytes
tylko znając „liczbę” znaków w ciągu? tjvar text = "Hello World!; var text_length = text.length; // pass text_length as argument to some method?
. I tylko w celach informacyjnych, reBuffer
- Właśnie natknąłem tej odpowiedzi , że omówionenew Blob(['test string']).size
, oraz w węźleBuffer.from('test string').length
. Może te też pomogą niektórym ludziom?To zadziała dla znaków BMP i SIP / SMP.
źródło
Możesz spróbować tego:
Mi to pasuje.
źródło