2014-09-22 70 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';