Perl 字符串操作和 utf8/unicode

Perl string manipulation and utf8/unicode

在人们开始将包含 utf8 字符的 Wikipedia 文本字符串复制并粘贴到输入字段之前,我一直认为这是一个简单的 Web 表单。我的 perl CGI 脚本打开一个 MySQL 数据库连接并设置

$DBH->{mysql_enable_utf8} = 1;
$DBH->do("set names 'utf8';");

我正在尝试使用 Encode 模块来解码、使用和编码目标输入值,但它没有像我预期的那样工作。网页设置为utf8字符集。

在这种情况下,我的目标字符串是 Baden-Württemberg [从列出德国城镇名称的维基百科页面复制]。发送请求后,我可以看到目标字符串为:Baden-W%C3%BCrttemberg。不过,这并没有很好地流经我的 CGI 脚本。

我有以下示例脚本:

#!/usr/local/bin/perl -w

use strict;
select(STDOUT);
$|++;

use feature 'unicode_strings';
use Encode;
use utf8;

binmode STDOUT, ":utf8";

my $thing = "Baden-Württemberg";
print STDOUT "$thing\n";

my $decodedThing = decode_utf8($thing);
print STDOUT encode_utf8($decodedThing) . "\n";

$thing 的值有一个 'u',上面有一个变音符号,就在“-W”之后。

当我 运行 脚本时,我得到:

# ./test.pl
Malformed UTF-8 character (unexpected non-continuation byte 0x72, immediately after start byte 0xfc) at ./test.pl line 13.
Baden-Wrttemberg
Baden-Wrttemberg

u-umlaut 去哪儿了?我如何取回它?

%C3%BCüurlencode。对于 MySQL,您不需要它,但在构建 URL.

时可能需要它

ü 当您将 utf8 字节作为 latin1 存储到 latin1 列时会发生。请提供 SHOW CREATE TABLE.

我认为你不需要 encode/decode_utf8 任何东西。

Malformed UTF-8 character (unexpected non-continuation byte 0x72, immediately after start byte 0xfc) at ./test.pl line 13.

表示你有十六进制 FC (这是 latin1 十六进制 ü),但你将字符串视为 utf8("unexpected ..") 72 是后面的 r.

底线:您在整个处理过程中都不是 utf8(手头的字节、SET NAMES、CHARACTER SET 等)。

问题 1

您告诉 Perl 您的源文件是使用 UTF-8 编码的。

use utf8;

事实并非如此。 ü 在您的文件中由 FC 而不是 C3 BC 表示。 (这就是您收到 "malformed" 消息的原因。)修复源文件的编码。

mv file.pl file.pl~ && piconv -f iso-8859-1 -t UTF-8 file.pl~ >file.pl

问题 2

以下内容毫无意义:

my $decodedThing = decode_utf8($thing);

因为use utf8;$thing已经被解码了。

问题 3

以下内容毫无意义:

print STDOUT encode_utf8($decodedThing);

你要求 Perl 自动编码每一个发送到 STDOUT 的东西,所以你是双重编码。

固定

#!/usr/local/bin/perl

use strict;
use warnings;
use utf8;
use open ':std', ':encoding(UTF-8)';

my $thing = "Baden-Württemberg";
printf "U+%v04X\n", $thing;     # U+[...].0057.00FC.0072.[...]
print "$thing\n";               # Baden-Württemberg

原来 Rick James 的最后一行 Bottom line: You are not utf8 throughout the processing (bytes in hand, SET NAMES, CHARACTER SET, etc). 是关键。我确实需要 Encode 模块,但仅适用于 DB 插入语句,a la:

if (!($sth->execute(encode('UTF-8', $_))) && $DBI::err != 1062) {
    die "DB execute failed :" . $DBI::err . ": " . $DBI::errstr;
}

谢谢大家