• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Konwersja kodu binarnego z UTF-8 do Tekstu

Object Storage Arubacloud
0 głosów
384 wizyt
pytanie zadane 8 kwietnia 2022 w JavaScript przez Riddick Bywalec (2,600 p.)
zamknięte 9 kwietnia 2022 przez Riddick

Chciałbym uzyskać konwerter działający identycznie jak tutaj: https://www.rapidtables.com/convert/number/binary-to-ascii.html chodzi o konwersje w kodowaniu w ASCII/utf-8 do kodu binarnego i na odwrót. Nie byłoby w tym nic trudnego gdyby nie fakt, że utf-8 operuje na zmiennej liczbie bitów przy zapisie co jest akurat mi potrzebne do jak najwiekszego skrócenia konwertowanego tekstu.

Przykładowo: kiedy wpisuje "a" otrzymuję "01100001"
Ale kiedy wpisuję "ą" to otrzymuję "11000100 10000101"

Oczywiście proces jest odwracalny.

Mój kod:

toBinaryRepr(str) {
    const text = new TextEncoder('utf-8')
    return Array.from(text.encode(str))
    .map(i => i
        .toString(2)
        .padStart(8, '0'))
    .join('')
  }

Ta funkcja zamienia mi tekst na utf-8 a następnie zmienia kod binarny

let result = input.split('')
      const chunks = []
      result.forEach((element, index) => {
        if(index % 8 === 0 || index === 0) chunks.push('')
        chunks[Math.floor(index / 8)] += element
      })
      // chunks.forEach((element, index) => {
        //   const binary = element
        //   const charCode = parseInt(binary)
        //   chunks[index] = charCode
        // })
      const utf8decoder = new TextDecoder('utf-8');
      const buffer = new Uint8Array(chunks.join(''))
      console.log(buffer)
      this.el.output.value = utf8decoder.decode(buffer)
      // this.el.output.value = buffer

A tutaj moje próby zdekodowania tego, w zmiennej input rzecz jasna siedzi kod binarny jako string.

Nie udało mi się podpatrzeć w kodzie podanej wyżej strony jak działa dokładnie ten mechanizm. Przeszukałem również wszelkie fora i artykuły w google w poszukiwaniu rozwiązania problemu zmiennych bajtów przy konwersji. Znalazłem tylko jedną poszlakę https://stackoverflow.com/questions/29902281/node-js-convert-binary-file-to-utf8: Jednak pomijając już, że funkcja użyta tam jest zdeprecjonowana i obecnie używa się Buffer.from to i tak to nie działa.

Wiem na 100%, że jest do do zrobienia ale nie wiem jak. Może istnieje jakiś sposób by skojarzyć, że dwa następujące po sobie bajty są jednym znakiem? Albo istnieje jakieś gotowe rozwiązanie o którym nie wiem? Wszystkie przykłady jakie sprawdziłem nie uwzględniają problemu zmiennej ilości bitów.

komentarz zamknięcia: Problem rozwiązany, jak to zwykle bywa przez drobne niedopatrzenie i brak wiedzy ominąłem prawidłowe rozwiązanie :D

1 odpowiedź

+1 głos
odpowiedź 8 kwietnia 2022 przez adrian17 Ekspert (345,620 p.)
wybrane 9 kwietnia 2022 przez Riddick
 
Najlepsza

Wszystkie przykłady jakie sprawdziłem nie uwzględniają problemu zmiennej ilości bitów.

Ale to w ogóle nie jest coś, czym o czym powinieneś myśleć. To jest dokładnie odpowiedzialność TextDecodera, po to jest; dlatego żaden przykład nic takiego nie robi.

Ogólnie potężnie przekombinowałeś. Mając tekst "1100010010000101", dzielisz go na części po 8 znaków używając string.slice, zamieniasz je na liczby z parseInt, pakujesz do UInt8Array i TextDecoder robi resztę. To jest z 5-6 linijek kodu ;)

To co tutaj zalinkowałeś: https://stackoverflow.com/questions/29902281/node-js-convert-binary-file-to-utf8 to też nie ma żadnego związku z Twoim problemem, bo oni mają faktyczne dane binarne, Ty masz zwykły string składający się ze znaków "0" i "1".

W sumie... teraz jak patrzę na to co napisałeś, z tym `Uint8Array(chunks.join(''))` to chyba dosłownie pomieszałeś sobie termin "danych binarnych"?

komentarz 8 kwietnia 2022 przez Riddick Bywalec (2,600 p.)
Już próbowałem, jednak to też nie działa, tak jak pisałem: przykładowo literka "a" potrzebuje 8 cyrf bo jej wartość liczbowa mieści się w zakresie 255 ale literka "ą" ma wartość 261 poza tym zakresem, więc nie da się jej zapisać w 8 znakach potrzeba 16. Tak więc, nie mogę wszystkiego podzielić na 8 bo wtedy zamiast 261 będę miał dwie cyfry (1 oraz 5) - tak mi pokazywało jak próbowałem tej metody. Niestety funkcja TextDecoder nie potrafi skojarzyć, że te dwie cyfry odnoszą się do jednego znaku z numerem 261.

Możliwe, że przekombinowałem bo siedzę nad tym już wiele godzin i próbowałem wszelkich sposobów. Główny problem z jakim się mierzę to to, że zwykłe znaki są zapisane normalnie w tych 8 zerach i jedynkach. Ale znaki np. polskie wymagają 16. Nie mam pojęcia w jaki sposób wykryć które ciągi są całym znakiem a które połową. Gdybym mógł je jakimś warunkiem wykryć mógłbym je połączyć i zrobić tak jak mówisz, zamienić na inta i na odpowiedni znak. Mógłbym też wszystkie znaki zapisać 16 stoma zerami i jedynkami. To jednak wydłużyłoby zapis dwukrotnie.

Masz również rację, że nie operuje tutaj na danych binarnych a na zwykłym tekście, możliwe, że też mnie to wprowadza w błąd jednak tak mi sobie to łatwiej obrazować.
komentarz 8 kwietnia 2022 przez adrian17 Ekspert (345,620 p.)
edycja 8 kwietnia 2022 przez adrian17

uh... co?

Nie, cały czas przekombinowujesz. Powtarzam, że w ogóle nie musisz myśleć o kodowaniu o zmiennej liczbie bajtów, tym się zajmuje TextDecoder!

Ale kiedy wpisuję "ą" to otrzymuję "11000100 10000101"

Te dwie wartości 8-bitowe to 196 i 133, więc...

> new TextDecoder().decode(new Uint8Array([196, 133]))
'ą'

Ładnie działa. Więc cały czas podtrzymuję to co wyżej napisałem.

Mając tekst "1100010010000101", dzielisz go na części po 8 znaków używając string.slice, zamieniasz je na liczby z parseInt, pakujesz do UInt8Array i TextDecoder robi resztę. To jest z 5-6 linijek kodu ;)

(i nie wiem skąd to 261 wziąłeś, to jest numer znaku w unicode ale to nie ma bezpośredniego związku z kodowaniem w utf-8)

1
komentarz 9 kwietnia 2022 przez Riddick Bywalec (2,600 p.)

No tak to faktycznie działa. I teraz zauważyłem dlaczego poprzednio mi to nie działało. Nie dodałem drugiego argumentu do funkcji parseInt. I faktycznie pomyliłem kodowanie utf-8 z kodami Ascii bo wcześniej zamieniałem znaki bez utf-8. Ale chyba tak to jest jak się za długo siedzi nad jednym problemem. Dzięki za uświadomienie mi tego smiley

const chunks = []
for(let i = 0; i < input.length; i += 8) {
  chunks.push(parseInt(input.slice(i, i + 8), 2))
}
this.el.output.value = new TextDecoder('utf-8').decode(new Uint8Array(chunks))

Uwzględniłem twoje rady i zoptymalizowałem ten kod, faktycznie dwie pętle były zupełnie niepotrzebne

Podobne pytania

0 głosów
1 odpowiedź 1,554 wizyt
0 głosów
2 odpowiedzi 561 wizyt
pytanie zadane 22 czerwca 2021 w C i C++ przez rottingham Nowicjusz (140 p.)
0 głosów
0 odpowiedzi 450 wizyt

92,661 zapytań

141,557 odpowiedzi

319,999 komentarzy

62,028 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...