10

我(迟来的)第一次测试 Unicode 水域并且我无法理解为什么编码的过程,然后解码一个阿拉伯字符串会产生分离出单词组成的单个字符的效果。

在下面的示例中,单词“ﻟﻠﺒﻴﻊ”由 5 个单独的字母组成:“ع”、“ي”、“ب”、“ل”、“ل”,从右到左书写。根据周围的上下文(相邻的字母),字母会改变形式


use strict;
use warnings;
use utf8;

binmode( STDOUT, ':utf8' );

use Encode qw< encode decode >;

my $str = 'ﻟﻠﺒﻴﻊ';                 # "For sale" 
my $enc = encode( 'UTF-8', $str );
my $dec = decode( 'UTF-8', $enc );

my $decoded = pack 'U0W*', map +ord, split //, $enc;

print "Original string : $str\n";     #  ل ل ب ي ع   
print "Decoded string 1: $dec\n"      #  ل ل ب ي ع
print "Decoded string 2: $decoded\n"; #  ل ل ب ي ع

附加信息

  • 将字符串粘贴到此帖子时,呈现反转,因此看起来像“ﻊﻴﺒﻠﻟ”。我正在手动反转它以使其看起来“正确”。正确的 hexdump 如下所示:

    $ echo "ﻟﻠﺒﻴﻊ" | hexdump
    0000000 bbef ef8a b4bb baef ef92 a0bb bbef 0a9f
    0000010
    
  • Perl 脚本的输出(根据 ikegami 的要求):

    $ perl unicode.pl | od -t x1
    0000000 4f 72 69 67 69 6e 61 6c 20 73 74 72 69 6e 67 20
    0000020 3a 20 d8 b9 d9 8a d8 a8 d9 84 d9 84 0a 44 65 63
    0000040 6f 64 65 64 20 73 74 72 69 6e 67 20 31 3a 20 d8
    0000060 b9 d9 8a d8 a8 d9 84 d9 84 0a 44 65 63 6f 64 65
    0000100 64 20 73 74 72 69 6e 67 20 32 3a 20 d8 b9 d9 8a
    0000120 d8 a8 d9 84 d9 84 0a
    0000127
    

    如果我只是打印$str

    $ perl unicode.pl | od -t x1
    0000000 4f 72 69 67 69 6e 61 6c 20 73 74 72 69 6e 67 20
    0000020 3a 20 d8 b9 d9 8a d8 a8 d9 84 d9 84 0a
    0000035
    

    最后(根据ikegami的要求):

    $ grep 'For sale' unicode.pl | od -t x1
    0000000 6d 79 20 24 73 74 72 20 3d 20 27 d8 b9 d9 8a d8
    0000020 a8 d9 84 d9 84 27 3b 20 20 23 20 22 46 6f 72 20
    0000040 73 61 6c 65 22 20 0a
    0000047
    
  • Perl 细节

    $ perl -v
    
    This is perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi
    (with 53 registered patches, see perl -V for more detail)
    
  • 输出到文件反转字符串:“ﻊﻴﺒﻠﻟ”


问题

我有一些:

  • 如何在打印时保留每个字符的上下文?

  • 为什么原始字符串作为单个字母打印到屏幕上,即使它没有被“处理”?

  • 打印到文件时,单词是相反的(我猜这是由于脚本的从右到左的性质)。有什么办法可以防止这种情况发生吗?

  • 为什么以下不成立:$str !~ /\P{Bidi_Class: Right_To_Left}/;

4

2 回答 2

3
  • StackOverflow 返回的源代码(使用 获取wget):

    ... ef bb 9f ef bb a0 ef ba 92 ef bb b4 ef bb 8a ...
    
    U+FEDF ARABIC LETTER LAM INITIAL FORM
    U+FEE0 ARABIC LETTER LAM MEDIAL FORM
    U+FE92 ARABIC LETTER BEH MEDIAL FORM
    U+FEF4 ARABIC LETTER YEH MEDIAL FORM
    U+FECA ARABIC LETTER AIN FINAL FORM
    
  • perl我从 StackOverflow 返回的源代码中得到的输出:

    ... ef bb 9f ef bb a0 ef ba 92 ef bb b4 ef bb 8a 0a
    ... ef bb 9f ef bb a0 ef ba 92 ef bb b4 ef bb 8a 0a
    ... ef bb 9f ef bb a0 ef ba 92 ef bb b4 ef bb 8a 0a
    
    U+FEDF ARABIC LETTER LAM INITIAL FORM
    U+FEE0 ARABIC LETTER LAM MEDIAL FORM
    U+FE92 ARABIC LETTER BEH MEDIAL FORM
    U+FEF4 ARABIC LETTER YEH MEDIAL FORM
    U+FECA ARABIC LETTER AIN FINAL FORM
    U+000A LINE FEED
    

    所以我应该得到源代码中的确切内容。

  • perl你得到的输出:

    ... d8 b9 d9 8a d8 a8 d9 84 d9 84 0a
    ... d8 b9 d9 8a d8 a8 d9 84 d9 84 0a
    ... d8 b9 d9 8a d8 a8 d9 84 d9 84 0a
    
    U+0639 ARABIC LETTER AIN
    U+064A ARABIC LETTER YEH
    U+0628 ARABIC LETTER BEH
    U+0644 ARABIC LETTER LAM
    U+0644 ARABIC LETTER LAM
    U+000A LINE FEED
    

    好的,所以你可能有一个有问题的 Perl(它可以反转和更改阿拉伯字符,而且只有那些),但你的资源很可能不包含你认为的内容。您需要检查哪些字节构成了您的源。

  • echo你得到的输出:

    ef bb 8a ef bb b4 ef ba 92 ef bb a0 ef bb 9f 0a
    
    U+FECA ARABIC LETTER AIN FINAL FORM
    U+FEF4 ARABIC LETTER YEH MEDIAL FORM
    U+FE92 ARABIC LETTER BEH MEDIAL FORM
    U+FEE0 ARABIC LETTER LAM MEDIAL FORM
    U+FEDF ARABIC LETTER LAM INITIAL FORM
    U+000A LINE FEED
    

    您从perl和从获得的内容存在显着差异echo,因此它们以不同的方式出现也就不足为奇了。


输出检查使用:

$ perl -Mcharnames=:full -MEncode=decode_utf8 -E'
   say sprintf("U+%04X %s", $_, charnames::viacode($_))
      for unpack "C*", decode_utf8 pack "H*", $ARGV[0] =~ s/\s//gr;
' '...'

(不要忘记交换 的字节hexdump。)

于 2013-01-31T07:57:37.237 回答
1

也许你的外壳有些奇怪?如果我将输出重定向到文件,结果将是相同的。请试试这个:

use strict;
use warnings;
use utf8;

binmode( STDOUT, ':utf8' );

use Encode qw< encode decode >;

my $str = 'ﻟﻠﺒﻴﻊ';                 # "For sale" 
my $enc = encode( 'UTF-8', $str );
my $dec = decode( 'UTF-8', $enc );

my $decoded = pack 'U0W*', map +ord, split //, $enc;

open(F1,'>',"origiinal.txt") or die;
open(F2,'>',"decoded.txt") or die;
open(F3,'>',"decoded2.txt") or die;

binmode(F1, ':utf8');binmode(F2, ':utf8');binmode(F3, ':utf8');

print F1 "$str\n";     #  ل ل ب ي ع   
print F2 "$dec\n";     #  ل ل ب ي ع
print F3 "$decoded\n";
于 2013-01-31T08:55:55.467 回答