15 Nov 2008

Perl i UTF + Locale

Czasami ja nie rozumiem jak działa Perl, dziś jest jeden z takich dni:


Oba kody robią to samo, jeden z localami drugi bez:
Code 1 - test.pl
#!/usr/bin/perl

use utf8;
use warnings;
use strict;
use locale;
#use POSIX q(setlocale);
#setlocale(&POSIX::LC_ALL, "pl");

# Uzywamy funkcji do kodowania/dekodowania
# utf8::encode($string);
# utf8::decode($string);

die "$0 testfile.txt" if scalar @ARGV <= 0; 

# pobieram caly plik
open( FH, '<', $ARGV[0] ) or die "Error: usage $0 file\n\n";
my $txt = do { local ($/);  };
close(FH);


utf8::decode($txt);
my @words = $txt =~ m/\w+/g;
map { utf8::encode($_) } @words;
print join(", ", @words)."\n";

Code 2 - test2.pl
#!/usr/bin/perl

use utf8;

use strict;
use warnings;

#use locale;
#use POSIX q(setlocale);
#setlocale(&POSIX::LC_ALL, "pl");
use open ':encoding(utf8)';
#use open ':locale';

die "$0 testfile.txt" if scalar @ARGV <= 0;

# pobieram caly plik
open( FH, '<', $ARGV[0] ) or die "Error: usage $0 file\n\n";

# tak samo jak use open 'encoding...'
#binmode FH, ":encoding(utf8)";
my $txt = do { local ($/);  };
close(FH);

my @words = $txt =~ m/\w+/g;
map { utf8::encode($_) } @words;
print join(", ", @words)."\n";

Wyniki:
$ locale
LANG=pl_PL.UTF-8
LC_CTYPE="pl_PL.UTF-8"
LC_NUMERIC="pl_PL.UTF-8"
LC_TIME="pl_PL.UTF-8"
LC_COLLATE="pl_PL.UTF-8"
LC_MONETARY="pl_PL.UTF-8"
LC_MESSAGES="pl_PL.UTF-8"
LC_PAPER="pl_PL.UTF-8"
LC_NAME="pl_PL.UTF-8"
LC_ADDRESS="pl_PL.UTF-8"
LC_TELEPHONE="pl_PL.UTF-8"
LC_MEASUREMENT="pl_PL.UTF-8"
LC_IDENTIFICATION="pl_PL.UTF-8"
LC_ALL=
$ cat input.txt
ęł@ąóąłð
łąśk
ala_ma_kota
$ perl test.pl input.txt
ęł, ą, ął, łąśk, ala_ma_kota
$ perl test2.pl input.txt 
ęł, ąóąłð, łąśk, ala_ma_kota

Tak na moje oko wyniki ze skryptu numer 2 są poprawne, ale dlaczego? Heh, czyżby ustawienie locali twierdziły, że ó nie jest litera słowa? No nie ważne, zapewne jakimś rozwiązaniem mogło by być ustawienie:
use POSIX qw(locale_h);
setlocale(LC_ALL,"pl_PL.UTF8");
ale mi się tego robić nie chciało :) Znalazłem tutorial o perlu i polskich znakach, może komuś pomoże - ja go nie stosowałem - w zupełności wystarczyła mi pragma use utf8;.

6 comments:

  1. Więcej informacji na temat UTF i Perla: http://ahinea.com/en/tech/perl-unicode-struggle.html

    ReplyDelete
  2. Know the difference between utf8 and UTF-8



    Things to remember:

    * The :utf8 encoding, and variations on it without a hyphen, is Perl's looser encoding.

    * Using UTF-8, in any case and with either a hyphen or underscore, is the strict, valid encoding and gives a warning for invalid sequences.

    * Only use the :encoding(UTF-8) and make its warnings fatal.


    So maybe it is time to consider change from:
    binmode $fh, ':utf8';

    to:
    binmode $fh, ':encoding(UTF-8)';

    ?

    ReplyDelete
  3. http://98.245.80.27/tcpc/scripts/perlunicook.html

    ReplyDelete