我遇到了Net::Cassandra::Easy
(基于Net::Cassandra
构建的)一个非常奇怪的UTF-8问题:写入Cassandra的UTF-8字符串在检索时出现乱码。
以下代码显示了问题:
use strict;
use utf8;
use warnings;
use Net::Cassandra::Easy;
binmode(STDOUT, ":utf8");
my $key = "some_key";
my $column = "some_column";
my $set_value = "\x{2603}"; # U+2603 is ☃ (SNOWMAN)
my $cassandra = Net::Cassandra::Easy->new(keyspace => "Keyspace1", server => "localhost");
$cassandra->connect();
$cassandra->mutate([$key], family => "Standard1", insertions => { $column => $set_value });
my $result = $cassandra->get([$key], family => "Standard1", standard => 1);
my $get_value = $result->{$key}->{"Standard1"}->{$column};
if ($set_value eq $get_value) {
# this is the path I want.
print "OK: $set_value == $get_value\n";
} else {
# this is the path I get.
print "ERR: $set_value != $get_value\n";
}
运行上面的代码$set_value eq $get_value
时评估为false
。我做错了什么?
答案 0 :(得分:4)
将use Encode;
添加到脚本的开头,并通过Encode::decode_utf8
传递变量。例如:
my $get_value = $result->{$key}->{"Standard1"}->{$column};
$get_value = Encode::decode_utf8($get_value);
输出:
OK: ☃ == ☃
当您将$set_value
设置为“\ x {2603}”时,Perl会检测宽字符并为您设置字符串编码为UTF-8。要确认这一点,请打印Encode::is_utf8($set_value)
的返回值。
不幸的是,一旦这个字符串进入Cassandra并再次退出,编码信息就会丢失。似乎Cassandra是编码不可知的。调用Encode::decode_utf8
告诉Perl你有一个包含UTF-8字节序列的字符串,并且应该将它转换为Perl的Unicode内部表示。正如jrockway指出的那样,你应该在将任何字符串发送到Cassandra之前调用Encode::encode_utf8
,尽管在大多数情况下Perl已经知道它们是UTF-8,例如,如果你打开了一个带有{{{ 1}}编码层。
如果您经常使用UTF-8,您可能希望通过Net :: Cassandra :: Easy编写一个包装器来自动执行此操作。
最后,除非您的Perl 源代码(变量名称,注释等)包含UTF-8字符,否则您不需要:utf8
。无论您是否指定use utf8;
,Perl都可以处理UTF-8 字符串。