代码之家  ›  专栏  ›  技术社区  ›  KJ7LNW

一些波斯语文本的宽字符印刷,但其他文本则没有

  •  0
  • KJ7LNW  · 技术社区  · 2 年前

    我在用 Google Translate

    “Geometry data card error”(几何数据卡错误)的翻译文本工作正常(示例1),但翻译“附加默认111卡”(示例2)会产生“宽字符”错误。

    这两个例子都可以从终端运行,它们只是打印出来的。

    我试过了 usual things 像这样,但无济于事:

    use utf8;
    use open ':std', ':encoding(UTF-8)';
    binmode STDOUT, ':encoding(UTF-8)';
    

    例1:这很有效

    perl -Mutf8 -le 'print "\x{d8}\x{ae}\x{d8}\x{b7}\x{d8}\x{a7}\x{db}\x{8c} \x{da}\x{a9}\x{d8}\x{a7}\x{d8}\x{b1}\x{d8}\x{aa} \x{d8}\x{af}\x{d8}\x{a7}\x{d8}\x{af}\x{d9}\x{87} \x{d9}\x{87}\x{d9}\x{86}\x{d8}\x{af}\x{d8}\x{b3}\x{db}\x{8c}"'
    خطای کارت داده هندسی
    

    示例2:这会产生宽字符警告并打印噪音

    perl -Mutf8 -le 'print "\x{d8}\x{a7}\x{d9}\x{81}\x{d8}\x{b2}\x{d9}\x{88}\x{d8}\x{af}\x{d9}\x{86} \x{db}\x{8c}\x{da}\x{a9} \x{da}\x{a9}\x{d8}\x{a7}\x{d8}\x{b1}\x{d8}\x{aa} \x{d9}\x{be}\x{db}\x{8c}\x{d8}\x{b4}\x{200c}\x{d9}\x{81}\x{d8}\x{b1}\x{d8}\x{b6} 111"'
    Wide character in print at -e line 1.
    # <terminal noise, not Farsi text>
    

    使用卷曲

    如果我对你提出同样的要求 curl 我明白了:

    curl 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=fa&hl=fa&dt=t&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&tk=xxxx&dt=dj&q=%41%70%70%65%6E%64%69%6E%67%20%61%20%64%65%66%61%75%6C%74%20%31%31%31%20%63%61%72%64'
    [[["افزودن یک کارت پیش\u200cفرض 111","Appending a default 111 card",null,null,3,null,null,[[]],[[["982c75c78c6c8e6005ec3a4021a7f785","tea_GrecoIndoEuropeA_en2elfahykakumksq_2021q3.md"]]]]],null,"en",null,null,null,1,[],[["en"],null,[1],["en"]]]
    

    注意 \u200c 在JSON输出中,上面是 "‌Zero Width Non-Joiner" unicode字符。什么时候 JSON::from_json 解析 \u200c 它爆炸了:

    perl -Mutf8 -MJSON -e 'print from_json("[\"\\u200c\"]")->[0];'
    Wide character in print at -e line 1.
    

    我可以这样“修复”它:

    my $c = $res->content;
    $c =~ s/\\u[0-9a-f]{4}//;
    my $json = from_json($c);
    

    然后输出文本是正确的(从右到左):

    افزودن یک کارت پیشفرض 111
    

    问题:这里发生了什么?

    • 这是Perl中的错误还是JSON中的错误?
    • 应该 \u200c 以其他方式正确解析?
    2 回复  |  直到 2 年前
        1
  •  1
  •   Shawn    2 年前

    这里发生了很多事情。我认为很多问题,尤其是在前两个例子中,都源于不理解perl的两种字符串模式(面向字节和面向Unicode码点)之间的区别。

    示例1是一个原始字节字符串,其中包含碰巧是UTF-8编码的字节,并以不变的方式传递;只要显示输出的终端需要UTF-8,它们就会被正确呈现。示例2有一个“宽”字符(值大于255),使其成为Unicode字符串,其中每个字符由一个 \x{NN} 大于127的数字是在UTF-8中编码为多个字节的Unicode码点。打印这会导致mojibake和警告,因为标准输出是面向字节的,没有翻译层。

    正如我在评论中所建议的,阅读 perluniintro (以及其他与unicode相关的文档)是学习如何工作的良好开端。


    但接下来是实际任务,从用户返回的JSON中提取文本 curl 命令。。。我会用 jq 如果这是一个shell脚本:

    $ curl ... | jq -r '.[0][0][0]'
    افزودن یک کارت پیش‌فرض 111
    

    与等效的perl one liner相比:

    $ curl ... | perl -CS -MJSON -lne 'print from_json($_)->[0][0][0]'
    افزودن یک کارت پیش‌فرض 111
    

    这个 -CS 参数告诉perl,标准输入、输出和错误都是UTF-8编码的。你也可以使用 -CO 使其成为标准输出,并使用 decode_json() 相反,它需要原始UTF-8编码字节,而不是Unicode字符串。

    在脚本中,而不是在一行程序中,使用OO接口 JSON 以及使用其方法调整输入字符串的编码方式,以及 open 布拉格马(或 binmode 或者一个编码层 打开 )而不是 -C 选择,才是出路。

        2
  •  0
  •   KJ7LNW    2 年前

    JSON对象需要启用utf8,它将修复 \u200c .感谢@Shawn为我指明了正确的方向:

    my $j = JSON->new;
    $j->utf8(1);
    my $json = $j->decode($c);
    

    现在JSON格式的文本内容 \u200c 正确翻译为 \xe2\x80\x8c 返回JSON哈希时。