Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Kodowanie znaków, chyba nietrywialne
Forum PHP.pl > Forum > PHP
skleps
Muszę pobrać dane z zewnętrznego pliku CSV.
Wszystko cacy, ale całość rozbija się o kodowanie znaków. Ten kto stworzył tego CSV zakodował tak znaki, że nie mogę dojść do ładu i składu, więc może ktoś z forum ma większe doświadczenie w tym hardkorze.
W sumie muszę zawartość zakodować do iso-8859-2 i nakarmić tym bazę MySQL. Sądząc po długości stringa, kodowanie jest dwubajtowe na znak, czyli np. "tekst" wg strlen zajmuje 11.
Więc po kolei:

1. Gdy CSV testowo importuję do Openoffice Calc, to prawidłowe polskie znaki są, gdy wybiorę "Unicode", gdy wybiorę "Unicode (UTF-7)" lub "Unicode (UTF-8)" to mam krzaki.

2. Grzegżółka twierdzi że kodowanie to "Kodowanie: Unicode UCS2 LE (Intel)", ale mb_convert_encoding($tekst,"ISO-8859-2","ucs-2le") daje w wyniku krzaczki (inne wariancje ucs też)

3. Z poziomu php funkcja mb_detect_encoding twierdzi że kodowanie to UTF-8 (lub ASCII gdy nie ma w polu polskich znaczków), ale mb_convert_encoding($tekst,"ISO-8859-2","UTF-8") daje w wyniku krzaczki (przeglądarka jest ustawiona na iso-8859-2).

4. rozzłoszczony zużytym na poszukiwania czasem zrobiłem pętęlkę:
  1. foreach (mb_list_encodings() as $value) {
  2. echo '<br>'. mb_convert_encoding($tekst,"ISO-8859-2",$value);
  3. }

i żaden wynik w przeglądarce nie wygląda prawidłowo.

Tak więc chwilowo nie mam pomysłu i jestem otwarty na propozycje jak mogę jeszcze ten temat ugryźć....





Crozin
Weź sobie całe źródło zrzuć do heksadecymalnej formy zapisu bajtów, a następnie w jakimś edytorze HEX (Notepad++ ma plugin, PSPad ma wbudowany) zobacz jakie bajty odpowiadają charakterystycznym znaczkom (np. "a", "ś", "<"). Wiedząc już jakie bajty reprezentują dany znak łatwo będzie znaleźć jakie jest to kodowanie.
skleps
Cytat(Crozin @ 12.12.2011, 23:45:03 ) *
Weź sobie całe źródło zrzuć do heksadecymalnej formy zapisu bajtów, a następnie w jakimś edytorze HEX (Notepad++ ma plugin, PSPad ma wbudowany) zobacz jakie bajty odpowiadają charakterystycznym znaczkom (np. "a", "ś", "<"). Wiedząc już jakie bajty reprezentują dany znak łatwo będzie znaleźć jakie jest to kodowanie.


Zdanie: Poznań

W hexie jest: 5000 6F00 7A00 6E00 6100 4401

Łódź = 4101 F300 6400 7A01

ę = 1901

ł = 4201

czyli na pierwszy rzut oka jest to jakiś unicode
Crozin
Wygląda to na UTF-16LE.
skleps
Myślałem podobnie, ale

  1. $tekst2 = mb_convert_encoding($tekst,"iso-8859-2","UTF-16LE");
  2. echo tekst2 ;


w przeglądarce ustawionej na iso-8859-2 wyświetla się: questionmark.gifquestionmark.gifquestionmark.gifquestionmark.gifquestionmark.gif?

Kawałek pliku CSv wrzuciłem pod adresem:
http://chomikuj.pl/iksow/Dokumenty/plikcsv,1241323892.csv
Crozin
W pliku mamy BOM (0xFF 0xFE), nazwy miast oddzielone średnikiem oraz znak nowej linii (CRLF) - wszystko wskazuje na to, że jest to UTF-16LE.
Sprawdź czy mb_convert_encoding / iconv poprawnie konwertuje tekst na ISO-8859-2 - ta sama metoda, podejrzyj wygenerowane bajty.
skleps
Na razie dostałem odpowiedź "na około" że jest to zapisany wynik zapytania z bazy.


  1. $tekst2 = mb_convert_encoding($tekst,"iso-8859-2","UTF-16LE");
  2. $fp = fopen('plikwynikowy', 'w');
  3. fwrite($fp, $tekst2);
  4. fclose($fp);


W pliku wynikowym dostaję 3F3F3F3F3F3F3F3F

Jeśli zas zrobię mb_convert_encoding($tekst,"iso-8859-2","UCS-2");

to w pliku Łódź = 41 3F 64 7A


Powoll zaczynam dojrzewać do myśli, że napiszę własną funkcję konwertującą, na chama wypisze sobie wszystkie literki i interesujące mnie znaczki...
Crozin
  1. $tekst2 = mb_convert_encoding($tekst,"iso-8859-2","UTF-16LE");
Sprawdziłem na swoim serwerze i działa to niemal bez problemów - nie radzi sobie jedynie z BOM-em, ale tego można od biedy przyciąć:
  1. $fileContents = substr($fileContents, 2);
Można też pominąć informację o kolejności bajtów (podając samo UTF-16), wtedy też odczyta to sobie na podstawie BOM-u i poprawnie go odczyta.

W takim przypadku radziłbym upewnić się czy aby na pewno problemem nie jest samo wyświetlanie tekstu w przeglądarce oraz czy aby na pewno PHP w Twoim przypadku wspiera UTF-16/UTF-16LE.
skleps
Cytat(Crozin @ 13.12.2011, 11:43:09 ) *
W takim przypadku radziłbym upewnić się czy aby na pewno problemem nie jest samo wyświetlanie tekstu w przeglądarce


Odpada, wtedy w wygenerowanym pliku byłoby dobrze, ale źle się wyświetlało.

Cytat(Crozin @ 13.12.2011, 11:43:09 ) *
czy aby na pewno PHP w Twoim przypadku wspiera UTF-16/UTF-16LE.


To może być prędzej - jak to można sprawdzić?
Serwer to vps na debianie, być może faktycznie czegoś mu brakować, bo instalacja w miarę standardowa.
skleps
Cytat(Crozin @ 13.12.2011, 11:54:30 ) *



no nie, to to od razu sprawdziałem wcześniej

  1. foreach (mb_list_encodings() as $value) {
  2. echo '<br>'. $value;
  3. }


i wynik:
  1. pass
  2. auto
  3. wchar
  4. byte2be
  5. byte2le
  6. byte4be
  7. byte4le
  8. BASE64
  9. UUENCODE
  10. HTML-ENTITIES
  11. Quoted-Printable
  12. 7bit
  13. 8bit
  14. UCS-4
  15. UCS-4BE
  16. UCS-4LE
  17. UCS-2
  18. UCS-2BE
  19. UCS-2LE
  20. UTF-32
  21. UTF-32BE
  22. UTF-32LE
  23. UTF-16
  24. UTF-16BE
  25. UTF-16LE
  26. UTF-8
  27. UTF-7
  28. UTF7-IMAP
  29. ASCII
  30. EUC-JP
  31. SJIS
  32. eucJP-win
  33. SJIS-win
  34. CP51932
  35. JIS
  36. ISO-2022-JP
  37. ISO-2022-JP-MS
  38. Windows-1252
  39. ISO-8859-1
  40. ISO-8859-2
  41. ISO-8859-3
  42. ISO-8859-4
  43. ISO-8859-5
  44. ISO-8859-6
  45. ISO-8859-7
  46. ISO-8859-8
  47. ISO-8859-9
  48. ISO-8859-10
  49. ISO-8859-13
  50. ISO-8859-14
  51. ISO-8859-15
  52. ISO-8859-16
  53. EUC-CN
  54. CP936
  55. HZ
  56. EUC-TW
  57. BIG-5
  58. EUC-KR
  59. UHC
  60. ISO-2022-KR
  61. Windows-1251
  62. CP866
  63. KOI8-R
  64. ArmSCII-8



Bardziej myślałem że to może jakiś błąd pliku, błąd generowania pliku lub błąd w obsłudze kodowania mimo tego, że na liście jest.
szmerak
Cytat(skleps @ 12.12.2011, 23:22:49 ) *
żaden wynik w przeglądarce nie wygląda prawidłowo.

Tak więc chwilowo nie mam pomysłu i jestem otwarty na propozycje jak mogę jeszcze ten temat ugryźć....


Zrobiłem kilka testów i równierz mam krzaczki na iso, tak więc ustawienia przeglądarki odpadają i ustawienia serwera także...
Gdy konwertowałem na utf8 to bodajże 3 były OK ale przy kodowaniu utf8..
skleps
No i chyba wiem, czemu Crozin ma dobrze a ja i ew. inni źle. Natrknąłem się w sieci na informację:

"Nie da się odczytać pliku, zawierającego polskie ogonki, zakodowanego w UTF-16LE (standard Windowsa, pliki wypluwane np. przez PowerShella) przy użyciu funkcji php file(). Tzn. można ale przy konwersji iconv() dostajemy i tak chińskie krzaki. Plik trzeba odczytać przy pomocy file_get_contents() i wtedy już ładnie konwertuje. Dopiero potem można bawić się w cięcie stringa w tablicę."

Sprawdzę to i ew. zamkniemy temat...




EDIT:
Sprawdziłem, faktycznie jest jakiś bug w php i podsumowanie:

Jeśli zaczytujemy plik tekstowy / csv z pliku zakodowanego "UTF-16LE" to należy plik wczytać funkcją file_get_contents() !
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.