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

[C] Wczytywanie i zapisywanie znaków specjalnych z pliku

Object Storage Arubacloud
0 głosów
1,206 wizyt
pytanie zadane 1 marca 2016 w C i C++ przez tirey93 Początkujący (380 p.)
Chcę napisać program który po wczytaniu tekstu z pliku będzie czytał każdy znak zawarty w pliku i na podstawie tego, jaki znak przeczyta wykona odpowiednie operacje(mniejsza z tym, jakie). Problem polega na tym że przy pracy w C mam do dyspozycji jedynie pliki w ASCII, która jest dość uboga. Nie ma tam polskich znaków czy nawet pewnych apostrofów. Przez ten fakt mój plik jest źle czytany. Czytałem w internecie, że musiałbym rozszerzyć kodowanie do uni albo utf-8 przez odpowiednie biblioteki, ale zupełnie nie wiem jak się za to zabrać. Może jest jakiś prosty sposób...

Bo jedyne czego potrzebuję, to proste porównanie znaków. "Czy 'ą' jest równe 'x'? Odp. brzmi "Nie" -> więc robi odpowiedni blok instrukcji i tak dalej. Nie da się jednak tego zrobić na charach które zawierają jedynie podstawowe ASCII.

Pytanie brzmi: Jak rozszerzyć chary do kodowania utf-8? Albo jak porównać znak pobrany z pliku(nienależący do ASCII) ze znakiem wytypowanym przeze mnie w kodzie(chodzi mi o jedyne true or false - jest taki sam lub jest inny)?

//Daruję sobie wstawianie kodu programu bo jest za ubogi by coś tu dodać. Dwa fopeny i while porównujący każdy znak.

2 odpowiedzi

+1 głos
odpowiedź 1 marca 2016 przez MetGang Nałogowiec (34,360 p.)

Problem znany mi doskonale. No cóż, na początek Cię pocieszę. W C++ sprawa nie wygląda łatwiej - wszystkie te streamy operujące na plikach też tak średnio współpracują z UTF-8. Lecz tak jak ja rozwiązałem ten problem w C++, tak samo da się w C.

https://pl.wikipedia.org/wiki/UTF-8

Trochę teorii. UTF-8 ma to do siebie, że zapisuje znaki z jak najmniejszą liczbą bajtów. A zostanie zapisane za pomocą jednego, Ą za pomocą dwóch,  za pomocą trzech. Czterobajtowe sekwencje też się znajdą.

Czyli to co trzeba zrobić to odkodować te 1-4 bajtowe sekwencje znaków i wpisać je do tablicy intów (int = 4 bajty) lub int*. I tak otrzymane znaki można już porównywać. W C++ ja to zapisuję do std::basic_string<unsigned int>.

W wyżej załączonym linku do wikipedii w kategorii Sposób kodowania masz ładnie opisane i pokazane na czym polega to kodowanie. Najprościej mówiąc, musisz rozpoznać na podstawie bitów, które nie są x'ami, ile bajtów przypada na znak, następnie wymazać ten bity (nie x'y). To co zostanie (czyli same x'y) poprzesuwać za pomocą << lub >> i poskładać za pomocą | (or bitowy) znak/liczbę w całość.

Zagmatwane to jest co prawda, ale programowanie to także tworzenie algorytmów. W razie wątpliwości - pytaj.

komentarz 1 marca 2016 przez tirey93 Początkujący (380 p.)
Okej, mam już się czego złapać. Pomyślmy. Mamy znak € który jest zapisany w unicode jako U+20AC. Muszę to zamienić na binarny unicode, potem uzupełnić wiodące zera i jedynki wg określonego schematu by ostatecznie dostać trzy 8bitowe liczby binarne. Byłyby to: znak[0]=226;znak[1]=130;znak[2]=172. Te trzy liczby odpowiadają €. Teraz muszę powyższy schemat powtórzyć dla każdego znaku i porównać go dla znaków zapisanych w kodzie programu. Jeśli wszystkie liczby do siebie pasują to znaczy że dany znak jest €.

Rozumiem zamysł. Mam nawet w głowie funkcję która przeliczałaby unicode na uff-8 i zapisywała to do 4ro-elementowej tablicy. Problemem jest wyciągnięcie informacji unicode'a(np. U+20AC) z kolejnych znaków pliku.Wiem, że nie znasz się na C bo dłubiesz w C++, ale może wiesz co mam wpisać by dokopać się do tej informacji?
komentarz 1 marca 2016 przez MetGang Nałogowiec (34,360 p.)

Lecz tak jak ja rozwiązałem ten problem w C++, tak samo da się w C.

Używam wskaźników i operacji bitowych. Jedyna różnica jest taka, że pobieram i zwracam stringa. Zresztą C nie jest aż tak straszny ;)

Całego swojego kodu nie wstawię, gdyż to jednak moja praca, ale dam kawałek odpowiedzialny za odkodowanie 2-bajtowego znaku (entery dla czytelności):

Aux=Src[v];
Aux&=0x1F;
Aux<<=6;
(*pDst)=Aux;

Aux=Src[++v];
Aux&=0x3F;
(*pDst)|=Aux;

Aux to unsigned, pDst to unsigned*, gdyż jak mówiłem operuję na std::basic_string<unsigned int>, z kolei Src to zwykły std::string, czyli w sumie const char*.

Najpierw do Aux przypisuje dany 8-bitowy char, następnie robię and bitowy z liczbą 0x1F żeby uzyskać iks'y -> 110xxxxx & 00011111 = 000xxxxx, czyli to co potrzebuję. Przesuwam w lewo za pomocą << o 6 pozycji, gdyż każdy kolejny bajt poza pierwszym zawiera 6 znaczących bitów (w przypadku 3 bajtowej sekwencji - przesuwałbym najpierw o 12, a potem o 6). Potem przypisuje do (*pDst), równie dobrze może to być zwykły int, którego później porównasz.
W następnym kroku biorę kolejny 8-bitowy char i przypisuje do Aux. Wymazuje to co niepotrzebne (10xxxxxx & 00111111 = 00xxxxxx) i za pomocą ora bitowego - wpisuje bity do (*pDst). Nie stosuje żadnego przesunięcia, gdyż jest to ostatni bit w sekwencji i jest on na swoim miejscu.

Co do sprawdzenia na jakiej ilości bajtów mam pracować to jest taki warunek (akurat do 3-bajtowego, gdyż do 2-bajtowego mam else ;p)

else if((Src[v]&0xE0)==0xE0)

Czyli 1110xxxx & 11100000 = 11100000

Chodzi o to, że jeśli bajt po skasowaniu iks'ów nadal będzie miał takie same wartości to oznacza, że jest to konkretny bajt informujący o danej ilości bajtów do obróbki.

Reasumując, wiem że wyjaśniam to w sposób pokręcony, ale mam nadzieję, że jakoś pomogłem. W razie wątpliwości - pisz ;)

0 głosów
odpowiedź 1 marca 2016 przez tirey93 Początkujący (380 p.)
Hej! Rozumiem że problem jest spory, ale może jakiś artykuł zaproponujecie? Ewentualnie co mam wpisać w google, aby szukać w dobrą stronę?

Podobne pytania

+1 głos
0 odpowiedzi 184 wizyt
0 głosów
1 odpowiedź 539 wizyt

92,555 zapytań

141,402 odpowiedzi

319,540 komentarzy

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

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy 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!

...