我正在运行 Perl 5.10.0 和 Postgres 8.4.3,并将字符串输入到数据库中,该数据库位于 DBIx::Class 后面。 .
这些字符串应该是 UTF-8,因此我的数据库是以 UTF-8 运行的。不幸的是,其中一些字符串很糟糕,包含格式错误的 UTF-8,所以当我运行它时,我遇到了异常DBI Exception: DBD::Pg::st execute failed: ERROR: invalid byte sequence for encoding "UTF8": 0xb5
我认为我可以简单地忽略无效的,然后担心格式错误的 UTF-8,因此使用此代码,它应该标记并忽略错误的标题。
if(not utf8::valid($title)){
$title="Invalid UTF-8";
}
$data->title($title);
$data->update();
然而 Perl 似乎认为字符串是有效的,但它仍然抛出异常。
如何让 Perl 检测到错误的 UTF-8?
最佳答案
首先,请遵循文档 - utf8
模块应该 仅限 用在'use utf8;'表格以表明您的源代码是 UTF-8 而不是 Latin-1。不要使用任何 utf8 函数。
Perl 区分字节和 UTF-8 字符串。在字节模式下,Perl 不知道也不关心您使用的是什么编码,如果您打印它,它将使用 Latin-1。以欧元符号 (€) 为例。在 UTF-8 中,这是 3 个字节,0xE2、0x82、0xAC。如果打印这些字节的长度,Perl 将返回 3。同样,它不关心编码。它可以是任何字节或任何编码,合法或非法。
如果您使用 Encode
模块并调用Encode::decode("UTF-8', $bytes)
你会得到一个新的字符串,它设置了所谓的 UTF8 标志。 Perl 现在知道你的字符串是 UTF-8 格式,并且会返回长度 1。utf8::valid
的问题仅适用于第二种类型的字符串。您的字符串可能是第一种形式,字节模式和 utf8::valid
只为字节形式的任何东西返回 true。这记录在 perldoc 中。
解决方案是让 Perl 将您的字节字符串解码为 UTF-8,并检测任何错误。这可以通过 FB_CROAK 来完成,正如 brian d foy 解释的那样:
my $ustring =
eval { decode( 'UTF-8', $byte_string, FB_CROAK ) }
or die "Could not decode string: $@";
然后,您可以捕获该错误并跳过那些无效字符串。
或者,如果您知道您的代码主要是 UTF-8,并且到处都有一些无效序列,您可以使用:
my $ustring = decode( 'UTF-8', $byte_string );
它使用默认模式
FB_DEFAULT
,用 U+FFFD 替换无效字符,Unicode 替换字符(带问号的菱形)。在大多数情况下,您可以将字符串直接传递给您的数据库驱动程序。某些驱动程序可能要求您首先将字符串重新编码回字节形式:
my $byte_string = encode('UTF-8', $ustring);
还有一些在线正则表达式,您可以在调用
decode
之前使用它们来检查有效的 UTF-8 序列。 (检查其他堆栈溢出答案)。如果您使用这些正则表达式,则无需进行任何编码或解码。最后请使用
UTF-8
而不是 utf8
在您调用 decode
.后者更加宽松,允许一些无效的 UTF-8 序列(例如 Unicode 范围之外的序列)通过。
关于perl - 如何让 Perl 检测错误的 UTF-8 序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2656401/