• 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

VPS Starter Arubacloud
0 głosów
366 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 (344,100 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 (344,100 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,505 wizyt
0 głosów
2 odpowiedzi 543 wizyt
pytanie zadane 22 czerwca 2021 w C i C++ przez rottingham Nowicjusz (140 p.)
0 głosów
0 odpowiedzi 416 wizyt

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

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!

...