2014-09-22 36 views
3

我想在Perl中将文本(印地语)转换为Unicode。我在CPAN中搜索过。但是,我无法找到我正在寻找的确切模块/方式。基本上,我正在寻找类似this的东西。在Perl中转换为unicode字符?

我输入的是:

इस परीक्षण के लिए है 

我的预期输出是:

\u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948 

如何在Perl实现这一目标?

给我一些建议。

+1

那你试试? – 2014-09-22 10:51:53

+0

我试过了Perl模块列表('Encode','Text :: Unidecode')。 – vara 2014-09-22 10:54:48

回答

7

试试这个

use utf8; 

my $str = 'इस परीक्षण के लिए है'; 

for my $c (split //, $str) { 
    printf("\\u%04x", ord($c)); 
} 
print "\n"; 
+0

简化代码。 – ikegami 2014-09-22 12:42:14

+1

注意:许多工具或编程语言(如Java,JavaScript和Python)使用的'\ uxxxx'表示法只支持4个十六进制数字,这使得这些转义符不适用于大于'U + FFFF'的代码点。常见的解决方法是将文本编码为UTF-16,然后将每个16位整数表示为“\ uxxxx”转义(即用代理对编码)。 Python还提供了另一种解决方法:32位'\ Uxxxxxxxx'表示法。您的代码可能会产生五位或更多位的通常不被识别的转义符,例如当应用于'$ str =“”'(U + 1F603张嘴笑脸)时。 – amon 2014-09-23 13:28:54

5

你并不真正需要的任何模块来做到这一点。 ord提取字符代码和printf格式化它作为4号补零十六进制是绰绰有余:

use utf8; 
my $str = 'इस परीक्षण के लिए है'; 
(my $u_encoded = $str) =~ s/(.)/sprintf "\\u%04x", ord($1)/sge; 
# \u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948 
+0

此解决方案在基本多语言平面之外的Unicode字符(即> U + FFFF)中存在潜在问题,因为您的代码将产生具有四个以上十六进制数字的转义符。有关详细信息,请参见[我对其他Oleg的答案的评论](https://stackoverflow.com/questions/25972258/converting-to-unicode-characters-in-perl#comment40710691_25972963)。 – amon 2014-09-23 13:32:13

3

如果你只想要一个简单的转换,你可以使用下面的过滤器

perl -CSDA -nle 'printf "\\u%*v04x\n", "\\u",$_' 
#or 
perl -CSDA -nlE 'printf "\\u%04x",$_ for unpack "U*"' 

像:

echo "इस परीक्षण के लिए है" | perl -CSDA -ne 'printf "\\u%*v04x\n", "\\u",$_' 
#or 
perl -CSDA -ne 'printf "\\u%*v04x\n", "\\u",$_' <<< "इस परीक्षण के लिए है" 

打印:

\u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948\u000a 

Unicode与代理对。

use strict; 
use warnings; 
use utf8; 
use open qw(:std :utf8); 

my $str = "if(\N{U+1F42A}+\N{U+1F410} == \N{U+1F41B}){ \N{U+1F602} = \N{U+1F52B} } # ορισμός "; 

print "$str\n"; 
for my $ch (unpack "U*", $str) { 
     if($ch > 0xffff) { 
       my $h = ($ch - 0x10000)/0x400 + 0xD800; 
       my $l = ($ch - 0x10000) % 0x400 + 0xDC00; 
       printf "\\u%04x\\u%04x", $h, $l; 
     } 
     else { 
       printf "\\u%04x", $ch; 
     } 
} 
print "\n"; 

打印

if(+ == ){ = } # ορισμός 
\u0069\u0066\u0028\u0020\ud83d\udc2a\u002b\ud83d\udc10\u0020\u003d\u003d\u0020\ud83d\udc1b\u0020\u0029\u007b\u0020\ud83d\ude02\u0020\u003d\u0020\ud83d\udd2b\u0020\u007d\u0020\u0023\u0020\u03bf\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2\u0020 
+0

此解决方案对于基本多语言平面以外的Unicode字符(即> U + FFFF)存在潜在问题,因为您的代码将产生具有四个以上十六进制数字的转义。有关详细信息,请参见[我对Oleg G的回答的评论](https://stackoverflow.com/questions/25972258/converting-to-unicode-characters-in-perl#comment40710691_25972963)。 – amon 2014-09-23 13:43:18

+0

@amon OP请求北印度语字符在BMP里面,但是你是正确的,并且为参考添加了一个带有代理对的例子... – jm666 2014-09-23 15:50:50

3

因为我留在其他的答案会如何功亏一篑的各种工具的预期提出一些看法,我想分享的外部编码字符的解决方案基本多语言平面作为两个转义对:""将变为\ud83d\ude03

这是通过:

  1. 编码字符串作为UTF-16,无字节顺序标记。我们明确选择一个永久性。在这里,我们任意使用big-endian形式。这产生八位位组的字符串(“字节”),其中两个八位位组形成一个UTF-16代码单元,以及两个或四个八位字节表示Unicode代码点。

    这是为了方便和性能进行;我们也可以自己确定UTF-16代码单元的数值。

  2. unpack荷兰国际集团得到的二进制串为16位整数,其表示每个UTF-16代码单元。我们必须尊重正确的字节顺序,所以我们使用n*模式作为unpack(即16位大端无符号整数)。

  3. 格式化每个码单元作为\uxxxx逃逸。

作为一个Perl子,这看起来像

use strict; 
use warnings; 
use Encode(); 

sub unicode_escape { 
    my ($str) = @_; 
    my $UTF_16BE_octets = Encode::encode("UTF-16BE", $str); 
    my @code_units = unpack "n*", $UTF_16BE_octets; 
    return join '', map { sprintf "\\u%04x", $_ } @code_units; 
} 

测试用例:

use Test::More tests => 3; 
use utf8; 

is unicode_escpape(''), '', 
    'empty string is empty string'; 

is unicode_escape("\N{SMILING FACE WITH OPEN MOUTH}"), '\ud83d\ude03', 
    'non-BMP code points are escaped as surrogate halves'; 

my $input = 'इस परीक्षण के लिए है'; 
my $output = '\u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948'; 
is unicode_escape($input), $output, 
    'ordinary BMP code points each have a single escape';