gor*_*lla 9 unicode perl utf-8
我正在运行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();
Run Code Online (Sandbox Code Playgroud)
但是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: $@";
Run Code Online (Sandbox Code Playgroud)
然后,您可以捕获该错误并跳过这些无效字符串.
或者,如果你知道你的代码大部分都是UTF-8,其中包含一些无效序列,你可以使用:
my $ustring = decode( 'UTF-8', $byte_string );
Run Code Online (Sandbox Code Playgroud)
它使用默认模式FB_DEFAULT,用U + FFFD替换无效字符,Unicode REPLACEMENT CHARACTER(带有问号的菱形).
在大多数情况下,您可以将字符串直接传递给数据库驱动程序.某些驱动程序可能要求您首先将字符串重新编码为字节形式:
my $byte_string = encode('UTF-8', $ustring);
Run Code Online (Sandbox Code Playgroud)
还有一些在线正则表达式可用于在调用之前检查有效的UTF-8序列decode(检查其他Stack Overflow答案).如果使用这些正则表达式,则无需进行任何编码或解码.
最后,请使用UTF-8而不是utf8在您的电话中decode.后者更宽松,允许允许一些无效的UTF-8序列(例如Unicode范围之外的序列).
你是如何得到你的弦?你确定Perl认为他们已经是UTF-8吗?如果它们尚未解码(即八位字节被解释为某种编码),则需要自己完成:
use Encode;
my $ustring =
eval { decode( 'utf8', $byte_string, FB_CROAK ) }
or die "Could not decode string: $@";
Run Code Online (Sandbox Code Playgroud)
更好的是,如果您知道您的字符串源已经是UTF-8,那么您需要将该源读取为UTF-8.查看您获得字符串的代码,看看您是否正确执行此操作.