Perl字符串操作及utf8/unicode

5

我本以为这只是一个简单的网页表单,但是当用户复制粘贴维基百科中包含UTF8字符的文本字符串到输入框时,问题就出现了。我的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的值在“-W”后面刚好有一个带分音符号的'u'。

当我运行脚本时,会得到以下输出:

# ./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 音标上的两个点去哪了?我该如何恢复它?
3个回答

3

问题1

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

use utf8;

这不是编码问题。在您的文件中,ü 是用 FC 而不是 C3 BC 表示的。(这就是为什么您会收到“格式错误”的消息。)请修复源文件的编码。

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

2

%C3%BCurlencode中的ü。但在MySQL中不需要这样,尽管当构建URL时可能需要。

如果将utf8字节存储为latin1并放入到latin1列中,就会出现ü的问题。请提供SHOW CREATE TABLE

我认为没有任何需要进行encode/decode_utf8的情况。

在./test.pl第13行遇到了错误的UTF-8字符(意外的非连续字节0x72,紧随起始字节0xFC)。

这表明您有FC(即ü的latin1十六进制),但您正在将该字符串视为utf8("unexpected .."),而72是后面的r

底线是: 在处理过程中未使用utf8 (手头上的字节、 SET NAMES、 CHARACTER SET等)。


创建表nameTokens ( id int(11) unsigned NOT NULL AUTO_INCREMENT, token varchar(128) NOT NULL, PRIMARY KEY (id), UNIQUE KEY token (token) ) ENGINE=InnoDB AUTO_INCREMENT=124 DEFAULT CHARSET=utf8 - 7 Reeds

0
原来Rick James的最后一行底线:在处理过程中你不是utf8(手头的字节,SET NAMES,字符集等)才是关键。我确实需要Encode模块,但只是为了数据库插入语句,比如:

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

感谢大家


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接