2010-09-04 24 views
11

Próbowałem już wszystkiego, co zalecane przez Google i StackOverflow (które mogłem znaleźć), w tym za pomocą kodowania. Mój kod działa, ale po prostu używa UTF8 i otrzymuję ostrzeżenia o szerokich znakach. Wiem, jak obejść te ostrzeżenia, ale nie używam UTF8 do niczego innego, więc chciałbym go po prostu przekonwertować i nie muszę zaadaptować reszty kodu, żeby sobie z tym poradzić. Oto mój kod:Konwertuj ciąg znaków UTF8 na ASCII w Perlu

my $xml = XMLin($content); 
# Populate the @titles array with each item title. 
my @titles; 
for my $item (@{$xml->{channel}->{item}}) { 
    my $title = Encode::decode_utf8($item->{title}); 
    #my $title = $item->{title}; 
    #utf8::downgrade($title, 1); 
    Encode::from_to($title, 'utf8', 'iso-8859-1'); 
    push @titles, $title; 
} 
return @titles; 

Nie znalazłem żadnych innych rzeczy, które wypróbowałem. Mam świadomość, że nie wiem, co tu robię. Po prostu chcę zakończyć na zwykłym starym łańcuchu ASCII. Wszelkie pomysły będą mile widziane. Dzięki.

Odpowiedz

18

Odpowiedź zależy od sposobu, w jaki chcesz użyć tytułu. Dostępne są 3 podstawowe sposoby:

  • Bajty reprezentujące łańcuch kodowany w UTF-8.

Jest to format, który powinien zostać użyty, jeśli chcesz przechowywać ciąg znaków zakodowany w UTF-8 poza aplikacją, czy to na dysku, czy też przesłać go przez sieć lub cokolwiek poza zakresem twojego programu.

  • Ciąg znaków Unicode.

Pojęcie znaków jest wewnętrzne dla Perla. Kiedy wykonujesz Encode::decode_utf8, próbuje się konwertować kilka bajtów na ciąg znaków, jak widzi Perl. Perl VM (i programista piszący kod Perla) nie mogą uzewnętrznić tej koncepcji, z wyjątkiem dekodowania bajtów UTF-8 na wejściu i kodowania ich do bajtów UTF-8 na wyjściu. Na przykład twój program otrzymuje dwa bajty jako dane wejściowe, o których wiesz, że reprezentują kodowane znaki UTF-8, na przykład 0xC3 0xB6. W takim przypadku decode_utf8 zwraca reprezentację, która zamiast dwóch bajtów, widzi jeden znak: ö.

Następnie można manipulować tym ciągiem w Perlu. Aby dodatkowo zilustrować różnicę rozważmy następujący kod:

my $bytes = "\xC3\xB6"; 
say length($bytes); # prints "2" 
my $string = decode_utf8($bytes); 
say length($string); # prints "1" 
  • Specjalny przypadek ASCII podzbiór UTF-8.

    ASCII to bardzo mały podzbiór kodu Unicode, w którym znaki z tego zakresu są reprezentowane przez jeden bajt. Konwersja Unicode do ASCII jest z natury stratną operacją, ponieważ większość znaków Unicode nie jest znakami ASCII. Jesteś albo zmuszony upuścić każdy znak w twoim łańcuchu, który nie jest w ASCII, albo spróbuj mapować z postaci Unicode na ich najbliższe odpowiedniki ASCII (co nie jest możliwe w ogromnej większości przypadków), gdy próbujesz przymusić Unicode ciąg do ASCII.

Skoro masz szerokie ostrzeżenia znaków, oznacza to, że starasz się manipulować (ewentualnie wyjściowe) znaki Unicode, które nie mogą być reprezentowane jako ASCII lub ISO-8859-1.

Jeśli nie ma potrzeby manipulowania tytułem z dokumentu XML w postaci ciągu, proponuję pozostawić go jako bajt UTF-8 (wspomnę, że należy uważać, aby nie mieszać bajtów i znaków w smyczki). Jeśli potrzebujesz manipulować nim, dekoduj, manipuluj, a na wyjściu koduj go w UTF-8.

Dla dalszego czytania, skorzystaj perldoc studiować perlunitut, perlunifaq, perlunicode, perluniintro i Encode.

+1

Zasadniczo jest tak, jak podejrzewałem. Moje zrozumienie tego problemu było daleko. Cóż, dziękuję za poświęcenie czasu na wyjaśnienia. Z jakiegoś powodu myślałem, że będę w stanie zmusić mój ciąg znaków UTF8 do jakiejś formy ASCII, która brzmi, jakby to był w najlepszym razie niechlujny hack. Myślę, że po prostu spienięję i zajmę się kodowaniem UTF8. –

+2

Jeśli musisz przekonwertować kodowanie UTF-8 do ASCII, potrzebujesz [Text :: Unidecode] (http://search.cpan.org/perldoc?Text:: Unidecode). – cjm

+0

@cjm Dokładnie to, czego potrzebowałem. Ten konwertuje znaki utf8 do najbliższej wizualnej alternatywy ASCII. Wielkie dzięki! –

2

Możesz użyć poniższego wiersza, aby po prostu pozbyć się ostrzeżenia. Zakłada to, że chcesz używać UTF8, co normalnie nie powinno być problemem.

binmode(STDOUT, ":encoding(utf8)");

+1

Nie potrzebujesz dwukropka, ale dopóki nie użyjesz 'use autodie' z Perl 5.10.1 lub nowszego, lepiej sprawdź wartość zwracaną, aby zobaczyć, że nie zrobiłeś żadnej literówki. Istnieje także zmienna 'PERL_UNICODE', którą można ustawić na' S'. Możesz go przesłonić w środowisku wykonawczym za pomocą flagi linii poleceń ** - C0 **. Częściej będziesz chciał do niego dodać, np. ** - CSAD **. Po prostu bądź ostrożny z tym, ponieważ teraz wszystkie twoje nieoznaczone strumienie są domyślnie ustawione na UTF-8, co często będzie cię wciągać. Więc nie jest to dobre domyślne. – tchrist

5

Chociaż jest to stara sprawa, ja właśnie spędziliśmy kilka godzin (!) Próbuje zrobić mniej więcej to samo! To znaczy: odczytaj dane z pliku XML UTF-8 i przekonwertuj te dane na stronę kodową Windows-1252 (mógłbym też użyć Latin1, ISO-8859-1 itd.), Aby móc tworzyć nazwy plików z literami akcentowanymi .

Po wielu eksperymentach, a nawet więcej wyszukanie, udało mi się w końcu uzyskać konwersji działa. "Sztuczka" polega na użyciu Encode :: kodowania zamiast Encode :: dekodowania.

Na przykład, biorąc pod uwagę kod w pierwotnym pytaniu poprawne (lub co najmniej jeden:-) sposób konwersji z UTF-8 może być:

my $title = Encode::encode("Windows-1252", $item->{title}); 

lub

my $title = Encode::encode("ISO-8859-1", $item->{title}); 

lub

my $title = Encode::encode("<your-favourite-codepage-here>", $item->{title}); 

mam nadzieję, że to pomoże innym o podobnym pr oblems!

Powiązane problemy