我正在使用谷歌翻譯通過 Perl 將一些錯誤代碼轉換為波斯語。波斯語就是一個這樣的例子,我也在其他語言中發現了這個問題——但對于這個討論,我將堅持一個例子:
“幾何資料卡錯誤”的翻譯文本作業正常(示例 1),但翻譯“附加默認 111 卡”(示例 2)給出“寬字符”錯誤。
這兩個示例都可以從終端運行,它們只是列印。
我已經嘗試過像這樣的常用方法,但無濟于事:
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=Appending a default 111 card'
[[["?????? ?? ???? ???\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 輸出中的“?零寬度非連接器” unicode char。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以其他方式正確決議嗎?
uj5u.com熱心網友回復:
這里發生了很多事情。我認為很多,尤其是在前兩個示例中,源于不了解 perl 的兩種字串模式(面向位元組和面向 Unicode 代碼點)之間的區別。
示例 1 是一個原始位元組字串,其中包含恰好是 UTF-8 編碼的位元組,并且未更改地傳遞;只要顯示輸出的終端期待 UTF-8,它們就會正確呈現。示例 2 有一個“寬”字符(值大于 255),使其成為 Unicode 字串,其中由\x{NN}大于 127 的數字表示的每個字符都是一個 Unicode 代碼點,在 UTF-8 中編碼為多個位元組。列印它會導致 mojibake 和警告,因為標準輸出是面向位元組的,沒有翻譯層。
正如我在評論中建議的那樣,閱讀perluniintro(以及其他與 unicode 相關的檔案)是了解事物如何作業的良好開端。
但在實際任務中,從您的命令回傳的 JSON 中提取文本......如果這是用于 shell 腳本curl,我會改用:jq
$ 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或編碼層open)而不是-C選項,是要走的路。
uj5u.com熱心網友回復:
JSON 物件需要啟用 utf8,它將修復\u200c. 感謝@Shawn 為我指明了正確的方向:
my $j = JSON->new;
$j->utf8(1);
my $json = $j->decode($c);
現在,當回傳 JSON 哈希時,JSON 格式的文本內容就像\u200c正確音譯一樣。\xe2\x80\x8c
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/464661.html
