【问题标题】:Split function returns weird characters拆分函数返回奇怪的字符
【发布时间】:2014-08-11 07:04:41
【问题描述】:

我在制作一个脚本时遇到了问题。简而言之,我正在使用 dbi 连接到本地数据库并执行一些查询。虽然这工作得很好,并且当我从选择查询等打印出返回值时,当我将 $firstName 拆分为一个数组并打印出数组时,我得到了奇怪的字符。请注意,我正在处理的表中的所有字段都只包含希腊字符并且是 utf8_general_ci。我玩过使用 utf8、使用编码、binmode、编码等,但拆分函数仍然返回 š 奇怪的字符,而在拆分之前,整个希腊词都打印得很好。我想这是由于缺少一些关于字符串编码或类似内容的编译指示,但真的找不到解决方案。提前致谢。 这是我正在描述的一段代码。 Perl 版本是 v5.14.2

@query = &DatabaseSubs::getStringFromDb(); 
print "$query[1]\n";  # prints the greek name fine 
@chars = split('',$query[1]); 
foreach $chr (@chars) { 
    print "$chr \n";  # prints weird chars 
}

here 分别是 print 和 foreach 的输出。

【问题讨论】:

    标签: perl


    【解决方案1】:

    您的数据是 utf8 格式,但 perl 不知道,因此每个 perl 字符只是存储在数据库中的多字节字符的一个字节。

    你告诉 perl 数据实际上是 utf8 格式:

    utf8::decode($query[1]);
    

    (尽管大多数数据库驱动程序都提供了一种在您看到代码中的数据之前自动执行此操作的方法)。完成此操作后, split 将正确地对实际字符进行操作。您可能还需要将输出文件句柄设置为预期 utf8 字符,否则它会尝试将它们降级为 8 位编码。

    【讨论】:

      【解决方案2】:

      默认情况下,Perl 假定您使用的是单字节字符。但您不是,在 UTF8 中,您使用的希腊字符大小为两个字节。因此split 将你的角色分成两半,而你会得到奇怪的角色。

      当字节进入程序时,您需要将它们解码为字符。一种方法是这样。

      use Encode;
      
      my @query = map { decode_utf8($_) } DatabaseSubs::getStringFromDb();
      

      (我还从子例程调用中删除了不必要且可能令人困惑的“&”。)

      现在@query 包含正确解码的字符串,split 将正确拆分为单个字符(*)。

      但是,如果您打印其中一个字符,则会收到“宽字符”警告。这是因为 Perl 的 I/O 层需要单字节字符。你需要告诉它期待 UTF8。你可以这样做:

      binmode STDOUT, ':utf8';
      

      您还可以考虑其他改进。例如,您可以将解码放入getStringFromDb 子例程中。我建议阅读perldoc perluniintroperldoc perlunicode 了解更多详情。

      (*) 是的,当你接触到两个字符的字素时,还有另一个层次的痛苦潜伏着,但我们现在先忽略它。

      【讨论】:

        【解决方案3】:

        问题是split('', $word)每个字节 上分割,而在utf8 中你可以有多字节字符。对于 ASCII 值小于 127 的字符,这很好,但任何超过 127 的字符都表示为多个字节。你实际上打印了一半的字符代码,因此它看起来像垃圾。

        【讨论】:

        • 我明白了。那么,您建议的解决方案是什么?
        • @user3759547 - 这个问题应该有点用:stackoverflow.com/questions/10302468/perl-substr-based-on-bytes
        • “问题是split('', $word) 在utf8 中可以包含多字节字符的每个字节上进行拆分。” - 编号split 拆分字符。但是您需要告诉它您的数据是 UTF8 格式或将采用单字节字符。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-29
        • 2019-07-05
        • 2017-07-04
        • 2018-03-11
        • 2019-07-27
        • 2016-10-11
        • 1970-01-01
        相关资源
        最近更新 更多