代码之家  ›  专栏  ›  技术社区  ›  U. Windl

printf与度数(°)字符对齐问题

  •  0
  • U. Windl  · 技术社区  · 7 年前

    我有一个类似的问题 How can I properly align UTF-8 strings with Perl's printf? 以下内容:

    我的(Linux)系统的区域设置默认为 LC_CTYPE=de_DE.UTF-8 我编写了一个Perl程序(使用Perl-5.26.1),它使用的不是Unicode字符,而是一些来自iso拉丁-1字符集(即 ° 例如)。 因此,我没有激活Perl脚本中的任何Unicode或区域设置功能。

    “一切”似乎都可以用一个排他性的理由来解决:我用的是 printf 格式 %-10s 对齐字符串,但不能按预期工作。

    在调试器中播放时,我发现了以下行为:

      DB<1> $s='X°X'
    
      DB<2> printf("_%3s_\n", $s)
    _X°X_
    

    到目前为止看起来还行…

      DB<3> printf("_%4s_\n", $s)
    _X°X_
    

    哎呀,不是吗 "_ X°X_" 是吗?

      DB<4> printf("_%5s_\n", $s)
    _ X°X_
    

    一个接一个?

      DB<5> x length($s)
    0  4
    

    不是吗 3 是吗?

      DB<8> x ord($s[1])
    0  0
      DB<9> x $s
    0  'X°X'
      DB<10>
    

    不应该 _ 编码为一个字节?我认为UTF-8将拉丁-1范围映射为Unicode。

    所以五月的问题是:

    1. 发生什么事?

    2. 它是Perl错误吗?

    3. 如果没有,如何修复格式和字符串长度?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Keith Thompson    7 年前

    UTF-8只将ASCII范围(0..127)映射到1字节。拉丁-1字符在0..255;utf-8范围内 不能 将它们全部映射到一个字节。如果这样做了,就不会有其他映射了。

    0到127之间的字符以1字节编码。
    128到2047之间的字符以2个字节编码。
    等等。

    https://en.wikipedia.org/wiki/UTF-8

    你需要 use utf8; 和 binmode STDOUT, ':encoding(UTF-8)'; 在Perl脚本中 STDIN 和 STDERR 只是为了保持一致性):

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use utf8;
    
    BEGIN {
        binmode STDIN,  ':encoding(UTF-8)';
        binmode STDOUT, ':encoding(UTF-8)';
        binmode STDERR, ':encoding(UTF-8)';
    }
    
    printf "|%-10s|\n", "x";
    printf "|%-10s|\n", "°";
    

    输出正确对齐:

    |x         |
    |°         |
    

    如果我也评论的话 使用UTF8; 或 binmode stdout,“:编码(utf-8)”; ,输出未对齐和/或度数字符显示不正确。

    报价 perldoc utf8 (文件 utf8 模块):

    “的” use utf8 “pragma告诉Perl解析器允许在 当前词汇范围中的程序文本。

    (这需要配置为显示UTF-8的输出设备或终端仿真器。)

        2
  •  2
  •   ikegami Gilles Quénot    7 年前

    Perl代码必须使用ASCII编码( no utf8; ,默认值)或utf-8( use utf8; )。

    ° 不在ASCII字符集中,而且您显然没有 使用UTF8; 或者,所以你的程序不可能包含 度 如你所说。

    首先,使用utf-8编码程序(如果还没有),并通过添加

    use utf8;   # The source code is encoded using UTF-8.
    

    其次,显然您也没有告诉Perl对您打印的内容进行编码。通过添加

    use open ':std', ':encoding(UTF-8)';   # The terminal provides/expects UTF-8.
    

    后者为在pragma范围内打开的文件设置默认编码。如果要避免这种情况,可以改用以下方法:

    BEGIN {   # The terminal provides/expects UTF-8.
       binmode(STDIN,  ':encoding(UTF-8)');
       binmode(STDOUT, ':encoding(UTF-8)');
       binmode(STDERR, ':encoding(UTF-8)');
    }