string - Perl 的默认字符串编码和表示

标签 string perl utf-8 character-encoding

在下面的:
my $string = "Can you \x{FB01}nd my r\x{E9}sum\x{E9}?\n";x{FB01}x{E9}是代码点。并且代码点通过编码方案编码为一系列八位字节。
所以字符è其中有代码点 \x{FB01}$string 字符串的一部分.但这是如何工作的?是 所有字符在这句话中(包括 ASCII 的)通过 UTF-8 编码?
如果是,为什么会出现以下行为?

my $str = "Some arbitrary string\n";  

if(Encode::is_utf8($str)) {  
        print "YES str IS UTF8!\n";  
}  
else {  
        print "NO str IT IS NOT UTF8\n";   
}  

这打印 "NO str IT IS NOT UTF8\n"另外 Encode::is_utf8($string)返回 true .$string以何种方式和 $str不同,一个被认为是 UTF-8而另一个不是?
无论如何,$str 的编码是什么? ? ASCII 码?这是 Perl 的默认设置吗? ?

最佳答案

在 C 中,字符串是八位字节的集合,但 Perl 有两种字符串存储格式:

  • 8 位值的字符串。
  • 72 位值的字符串。 (实际上,仅限于 32 位或 64 位。)

  • 因此,您不需要编码代码点以将它们存储在字符串中。
    my $s = "\x{2660}\x{2661}";
    say length $s;                            # 2
    say sprintf '%X', ord substr($s, 0, 1);   # 2660
    say sprintf '%X', ord substr($s, 1, 1);   # 2661
    

    (在内部,称为“utf8”的 UTF-8 扩展用于存储 72 位字符的字符串。除了意识到性能影响外,您不需要知道这些,但存在暴露这一事实的错误。 )

    编码器is_utf8报告标量包含哪种类型的字符串。这是一个除了调试我之前提到的错误之外完全没有用的功能。
  • 一个 8 位的字符串可以存储 "abc" 的值(或 OP 中的字符串 $str ),因此 Perl 使用了更高效的 8 位 (UTF8=0) 字符串格式。
  • 8 位字符串不能存储 "\x{2660}\x{2661}" 的值(或 OP 中的字符串 $string ),因此 Perl 使用 72 位(UTF8=1)字符串格式。

  • 零是零,无论它存储在浮点数、有符号整数还是无符号整数中。类似地,字符串的存储格式不传达有关字符串值的信息。
  • 您可以像存储 72 位字符串一样轻松地将代码点存储在 8 位字符串中(如果它们足够小)。
  • 您可以像存储 8 位字符串一样轻松地将字节存储在 72 位字符串中。

  • 实际上,Perl 会在两种格式之间随意切换。例如,如果您连接 $string$str ,您将获得 72 位格式的字符串。

    您可以使用内置函数 utf8::downgrade 更改字符串的存储格式和 utf8::upgrade ,如果您需要解决错误。
    utf8::downgrade($s);  # Switch to strings of  8-bit values (UTF8=0).
    utf8::upgrade($s);    # Switch to strings of 72-bit values (UTF8=1).
    

    您可以使用 Devel::Peek 查看效果。
    >perl -MDevel::Peek -e"$s=chr(0x80); utf8::downgrade($s); Dump($s);"
    SV = PV(0x7b8a74) at 0x4a84c4
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x7bab9c "\200"\0
      CUR = 1
      LEN = 12
    
    >perl -MDevel::Peek -e"$s=chr(0x80); utf8::upgrade($s); Dump($s);"
    SV = PV(0x558a6c) at 0x1cc843c
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      PV = 0x55ab94 "\302\200"\0 [UTF8 "\x{80}"]
      CUR = 2
      LEN = 12
    

    关于string - Perl 的默认字符串编码和表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17222685/

    相关文章:

    c - 对文件中的字符串进行标记

    string - 给定一个字符串 A 和一组字符串 S。需要找到一个最佳方法来找到 A 的前缀,该前缀不是 s 中任何字符串的前缀

    testing - 用于测试的备用 Perl 环境

    python - 替换编码无法识别的字符

    Javadoc 错误 : unmappable character for encoding ASCII

    string - 在groovy中用$替换一个单词

    java - 如何在没有正则表达式的情况下解析字符串

    perl - 如何搜索包含特定关键字的 Instagram 评论

    string - 当 $STRING 以 "\t\t"结尾时,如何让 split(/\t/, $STRING) 检测空值?

    ruby-on-rails - Ruby 方法从 UTF-8 国际字符中删除重音符号