Leser: 28
Quotewenn man mit einer webseite arbeitet, die utf-8 ausliefert und empfängt, sollte man die daten zur verarbeitung dekodieren, da sonst stringmanipulationen wie uc(), substr() usw. nicht korrekt arbeiten...
2011-08-02T17:51:12 rostiDas Verhalten von substr() wird vom pragma utf8 bestimmt.
QuoteWas genau meinst Du mit dekodieren?
1 2 3 4 5
use strict; use utf8; my $s = 'äöüß'; printf "%s\n", substr $s, 0, 2; # 2 Zeichen # ohne use utf8 werden 2 Bytes ausgegeben
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ perl -wE'
use utf8;
use CGI;
use Devel::Peek;
use Encode;
my $cgi = CGI->new;
my $test = $cgi->param("test");
Dump $test;
my $x = substr($test, 0, 1);
Dump $x;' "test=%C3%A4"
SV = PVMG(0x81a6fe8) at 0x81ada78
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
IV = 0
NV = 0
PV = 0x8309588 "\303\244"\0
CUR = 2
LEN = 4
SV = PV(0x82a8758) at 0x82aa8c0
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x8193620 "\303"\0
CUR = 1
LEN = 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ perl -wE'
use utf8;
use CGI;
use Devel::Peek;
use Encode;
my $cgi = CGI->new;
my $test = decode_utf8 $cgi->param("test"); # <--- decode
Dump $test;
my $x = substr($test, 0, 1);
Dump $x;' "test=%C3%A4"
SV = PV(0x8872868) at 0x8777a80
REFCNT = 1
FLAGS = (PADMY,POK,pPOK,UTF8)
PV = 0x8834e80 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
SV = PV(0x8872858) at 0x8841818
REFCNT = 1
FLAGS = (POK,pPOK,UTF8)
PV = 0x8834e90 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
Quotech sagte ja, use utf8 wirkt sich nur auf variablen aus, die direkt im skript stehen.
es geht aber bei einer webseite (auch) um strings, die von aussen kommen.
QuoteThe "use bytes" pragma disables character semantics for the rest of the lexical scope in which it appears.
QuoteThe "use utf8" pragma tells the Perl parser to allow UTF-8 in the
program text in the current lexical scope (allow UTF-EBCDIC on EBCDIC
based platforms). The "no utf8" pragma tells Perl to switch back to
treating the source text as literal bytes in the current lexical scope.
Do not use this pragma for anything else than telling Perl that your
script is written in UTF-8.
Quotebei CGI-skripten und Datenbank-Operationen braucht man daher Encode, um stringmanipulationen korrekt durchzuführen.
1 2 3 4
my @len = unpack "U*", $c->param('text'); # CodePoint-Array my $bytes = pack "U*", @len; # Zeichen wieder aus Codepoints printf "Text: %s, Length: %u\, len2: %u, len3: %u, Substr: %s\n", $c->param('text'), length $c->param('text'), scalar @len, length $bytes, substr $bytes, 0,1;
Guest werUnd darum Encode nutzen.
1 2 3 4 5 6 7 8
use CSU; # Character Semantics for UTF-8 use strict; use warnings; my $csu = CSU->new('äöü'); print $csu->substr(0,1); # weitere String-Methoden sind vorerst length und uc
2011-08-02T17:51:12 rostiDas Verhalten von substr() wird vom pragma utf8 bestimmt.
QuoteDo not use this pragma for anything else than telling Perl that your script is written in UTF-8.
QuoteWas genau meinst Du mit dekodieren?
QuoteDas Verhalten von substr() wird vom pragma utf8 bestimmt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ perl -wE'
use Devel::Peek;
use Encode;
use utf8;
my $str = "ä";
my $substr = substr($str, 0, 1);
Dump $substr;
$str = encode_utf8($str);
$substr = substr($str, 0, 1);
Dump $substr;
'
SV = PV(0xa0ff780) at 0xa11cab0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK,UTF8)
PV = 0xa1209b8 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
SV = PV(0xa0ff780) at 0xa11cab0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0xa1209b8 "\303"\0
CUR = 1
LEN = 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ perl -wE'
use Devel::Peek;
use utf8;
use Encode;
my $str = "ä";
my $substr = substr($str, 0, 1);
Dump $substr;
no utf8;
$substr = substr($str, 0, 1);
Dump $substr;
'
SV = PV(0x8af9780) at 0x8b16aa0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK,UTF8)
PV = 0x8b1a9a8 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
SV = PV(0x8af9780) at 0x8b16aa0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK,UTF8)
PV = 0x8b1a9a8 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
Quotewarum willst du es immer wieder durchkauen?
use utf8 verändert, wie variablen kodiert sind.
substr entscheidet nur danach, wie variablen kodiert sind
1
2
3
4
5
6
7
8
9
10
11
12
$ perl -wE'use Devel::Peek;
use utf8;
use Encode;
my $str = "\303\244";
my $substr = substr($str, 0, 1);
Dump $substr;'
SV = PV(0x9b9f6c8) at 0x9bbca70
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x9bc0978 "\303"\0
CUR = 1
LEN = 4
my $str = "\303\244";
Quotedass Pragma utf8 das Verhalten aller Stringfunktionen bestimmt, sofern diese auf Strings zugreifen, die INTERN im Script selbst notiert sind und das Script mit Zeichenkodierung 'utf-8' gespeichert wurde.
2011-08-03T11:23:35 rostiarbeitet Perl intern und damit ist das Pragma nicht wirksam ;)
1 2 3 4 5 6 7 8 9
# Perl-intern, byte semantic my $s = sprintf "%s", "\303\244\303\244",; print length($s), "\n"; # number of bytes # force character semantic my @cp = unpack "U0U*", $s; # characters to codepoints my $chr = pack "U0U*", @cp; # codepoints to characters # jetzt betrachtet Perl die Zeichen nicht mehr als bytes print length $chr; # number of characters
QuoteDas Verhalten von substr() wird vom pragma utf8 bestimmt.
Quotemit dem Zusatz, dass Pragma utf8 das Verhalten aller Stringfunktionen bestimmt, sofern diese auf Strings zugreifen, die INTERN im Script selbst notiert sind und das Script mit Zeichenkodierung 'utf-8' gespeichert wurde.
Quotemit dem zusatz, dass es sich wiederum nicht auf substr auswirkt, wenn perl "intern arbeitet", was dann passiert, wenn "die zeichen nicht als solche notiert sind"
1 2 3 4
use utf8; my $s = 'äöü'; no utf8; print length $s; # immer noch character semantic!!!!
2011-08-03T12:24:51 LinuxerWarum Vorsicht? Macht doch genau das, was es soll.
edit: Es setzt für die Variable $s den Merker, dass da utf8 drin steckt. Dieser Merker bleibt auch noch nach einem no utf8; bestehen...
2011-08-03T11:43:19 GwenDragonWenn du es genau weißt, erkläre doch mal warum die Bytesequenz \303\244 nicht dasselbe wie ä in UTF8 ist.
1 2 3 4 5
# Jetzt nehmen wir mal die Bytes , C3 A4 für das Zeichen 'ä' # beachte Schablone "C", es werden bytes erzeugt my $str = pack "C*", 0xC3, 0xA4; # Es ist zu erwarten, das Perl-intern die byte-semantic gilt print length($str), "\n"; # Und ja: Es stimmt ;)
2011-08-03T10:19:05 rostiQuoteDas Verhalten von substr() wird vom pragma utf8 bestimmt.
Ist nicht falsch, mit dem Zusatz, dass Pragma utf8 das Verhalten aller Stringfunktionen bestimmt, sofern diese auf Strings zugreifen, die INTERN im Script selbst notiert sind und das Script mit Zeichenkodierung 'utf-8' gespeichert wurde.
QuoteTeste es doch einfach mal selbst.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use strict;
use warnings;
use Encode qw/encode_utf8/;
use charnames qw/:full/;
use 5.010; # nur fuer say() benoetigt
my $chars = "\N{LATIN SMALL LETTER A WITH DIAERESIS}\N{LATIN SMALL LETTER O WITH DIAERESIS}";
my $bytes = encode_utf8 $chars;
{
use utf8;
say 'With utf8';
say encode_utf8(uc($chars)), " ", uc($bytes);
say encode_utf8(substr($chars, 0, 2)), " ", substr($bytes, 0, 2);
}
{
no utf8;
say 'Without utf8';
say encode_utf8(uc($chars)), " ", uc($bytes);
say encode_utf8(substr($chars, 0, 2)), " ", substr($bytes, 0, 2);
}
__END__
With utf8
ÄÖ äö
äö ä
Without utf8
ÄÖ äö
äö ä
QuoteBtw., in meiner Perl-Version (5.6.1. und 5.8.8) verlangt uc() das Pragma utf8, auch bei Strings, die von außerhalb (DB, CGI) in das Script hineinkommen
1
2
$ echo -e "\xC3\xB5" | perl -wE 'binmode STDIN, ":utf8"; $_ = <>; chomp; say length'
1
QuoteDu siehst, das utf8-Pragma hat keinerlei Einfluss auf das Ergebnis des String-Operationen. Wenn man substr() und uc() bytes liefert, arbeiten sie auf bytes, wenn man ihnen codepoints liefert, arbeiten sie auf codepoints, voellig unabaehngig vom utf8-Pragma.
Ueberzeugt?
2011-08-03T15:22:27 rostiQuoteDu siehst, das utf8-Pragma hat keinerlei Einfluss auf das Ergebnis des String-Operationen. Wenn man substr() und uc() bytes liefert, arbeiten sie auf bytes, wenn man ihnen codepoints liefert, arbeiten sie auf codepoints, voellig unabaehngig vom utf8-Pragma.
Ueberzeugt?
Ja, natürlich, keine Frage ;)
print length 'äöü';
2011-08-03T16:18:40 rostiNatürlich hat Pragma utf8 Einfluss auf das Verhalten von Stringfunktionen.
Ohne Pragma liefert
die Anzahl der Bytes, mit Pragma die Anzahl der Zeichen, die hier in diesem Fall direkt im Script notiert und utf-8-kodiert sind.Code (perl): (dl )print length 'äöü';
2011-08-03T16:18:40 rostiNatürlich hat Pragma utf8 Einfluss auf das Verhalten von Stringfunktionen.
QuoteWoher soll Perl wissen, dass es sich überhaupt um menschenlesbare Zeichen handelt?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ perl -wE'
use Devel::Peek;
my $str = "ä";
use utf8;
my $sub = substr($str, 0, 1);
say length $sub;
Dump $sub;'
1
SV = PV(0x84556c8) at 0x8472aa8
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x8476970 "\303"\0
CUR = 1
LEN = 4
2011-08-03T16:47:37 rostiDu hast erst den String und dann das Pragma utf8 notiert. Wenn sich das Pragma auf den String auswirken soll, muss es VORHER notiert sein.
2011-08-03T17:45:18 GwenDragonDa setzt einer Rost an. ;)
Quote... q.e.d.
2011-08-05T08:18:24 rostiQuote... q.e.d.
Btw., ich habe Moritz zugestimmt, dass Perl-Intern eine Zeichenkette als UTF-8-kodierte Zeichenkette repräsentiert wird, wenn diese Zeichenkette aus Codepoints erzeugt wird.
QuoteMit dieser Erkenntnis ist es möglich, auf das Pragma utf8 vollständig zu verzichten.
2011-08-04T05:58:36 rostiWenn ich das nun richtig verstanden habe, funktioniert das utf8-Pragma so, dass es intern (Symboltabelle)
Quoteein Flag auf Literale setzt.
QuoteEine andere Möglichkeit, diesen Flag zu setzen, z.B. auf Literale aus CGI-Parametern: pack/unpack mit Schablone "U".
my $bytes = pack 'U0U*', @codepoint_liste;
2011-08-04T05:58:36 rostiWenn ich das nun richtig verstanden habe, funktioniert das utf8-Pragma so [...]
QuoteDu verstehst das Pragma utf8 nicht.
1 2 3 4 5 6 7 8
#!/usr/bin/perl -w use strict; use warnings; print length('ä'),"\n"; use utf8; print length('ä'),"\n"; no utf8; print length('ä'),"\n";
Quote1
Malformed UTF-8 character (unexpected end of string) in length at test.pl line 6.
0
1
1
2
3
4
5
6
7
8
9
10
11
12
13
DESCRIPTION
The "use utf8" pragma tells the Perl parser to allow UTF-8 in the
program text in the current lexical scope (allow UTF-EBCDIC on EBCDIC
based platforms). The "no utf8" pragma tells Perl to switch back to
treating the source text as literal bytes in the current lexical scope.
Do not use this pragma for anything else than telling Perl that your
script is written in UTF-8. The utility functions described below are
directly usable without "use utf8;".
Because it is not possible to reliably tell UTF-8 from native 8 bit
encodings, you need either a Byte Order Mark at the beginning of your
source code, or "use utf8;", to instruct perl.
2011-08-10T16:10:00 biancaAber noch eine Frage: Wenn ich ein Script in UTF8 speichere, wieso brauche ich dann noch use utf8? Ist das zur besseren Lesbarkeit und Klarheit oder hat das noch einen Zusatzeffekt?
1 2 3 4
use utf8; print "Content-Type: text/plain; charset=UTF-8\n\n"; # zum Webserver binmode STDOUT, ':utf8'; print 'ä';
1 2
print "Content-Type: text/plain; charset=UTF-8\n\n"; # zum Webserver print 'ä';