UTF-8のペルシャ数字をASCIIのヨーロッパ数字に変換するにはどうすればよいですか?


16

ペルシア数字で۰۱۲۳۴۵۶۷۸۹0123456789、ヨーロッパの数字と同等です。

ペルシャ番号(in UTF-8)をASCII に変換するにはどうすればよいですか?

例えば、私が欲しい۲۱になるために21


1
面白い、のように思えるecho "۰۱۲۳۴۵۶۷۸۹" | iconv -f UTF-8 -t ascii//TRANSLITそれを処理しません...
Kusalananda

@Kusalanandaしない働いた
بارپابابا

3
@Kusalananda:それは本当に予想外のことですか?私が理解したようにiconv、異なるエンコーディングの文字をマップすることはここにありますが、これらはASCIIでは同等の文字(東アラビア数字)ではありませんが、十分に類似したものに変換することができますが、それは一方向のみです。
phk

3
まあ、私は何iconvができて何ができなかったのかよくわかりませんでした。私はthotの使用//TRANSLITが役立つことを望んでいましたが、それはしませんでした。
クサラナナンダ

1
順序を逆にする必要もありますか?アラビア数字は右から左にリトルエンディアンで書かれており、ラテン数字は左から右にビッグエンディアンで書かれていることを知っています(印刷または画面では似ていますが、メモリでは逆になります)。ペルシャ語は同じですか?
トビースパイト

回答:


6

ペルシャ数字のUNICODEコードポイントは連続しており、0から9まで順序付けられているという事実を利用できます。

$ printf '%b' '\U06F'{0..9}
۰۱۲۳۴۵۶۷۸۹

つまり、最後の16進数は10進数値です。

$ echo $(( $(printf '%d' "'۲") & 0xF ))
2

これにより、この単純なループが変換ツールになります。

#!/bin/bash
(   ### Use a locale that use UTF-8 to make the script more reliable.
    ### Maybe something like LC_ALL=fa_IR.UTF-8 for you?.
    LC_ALL=en_US.UTF-8
    a="$1"
    while (( ${#a} > 0 )); do
        # extract the last hex digit from the UNICODE code point
        # of the first character in the string "$a":
        printf '%d' $(( $(printf '%d' "'$a") & 15 ))
        a=${a#?}    ## Remove one character from $a
    done
)
echo

使用方法:

$ sefr.sh ۰۱۲۳۴۵۶۷۸۹
0123456789

$ sefr.sh ۲۰۱
201

$ sefr.sh ۲۱
21

このコードは、アラビア数字とラテン数字も変換できることに注意してください(混在していても)。

$ sefr.sh ۴4٤۵5٥۶6٦۷7٧۸8٨۹9٩
444555666777888999

$ sefr.sh ٤٧0٠٦7١٣3٥۶٦۷
4700671335667

非常に非常に感謝が、これは非常に素晴らしいソリューションです,,と私は、このコマンドで,,疑問を持っているのprintf「%D」「"0'二重引用符を使用する理由?
بارپابابا

@Babyyこれは二重引用符ではなく、一重引用符で始まる引数をprintfに与える方法です。としても書かれている可能性があります'"۰'。理由は、引数が単一引用符'または二重引用符で始まる場合、printfがUNICODEコードポイントを与えるためです"このリンクの少し前に「先頭の文字が単一引用符または二重引用符である場合」というテキストを検索します

@Babyyこのコードは、ペルシャ語、アラビア語、およびラテン語(混合であっても)を変換するように拡張されています。

27

数字の固定セットであるため、手動で行うことができます。

$ echo ۲۱ | LC_ALL=en_US.UTF-8 sed -e 'y/۰۱۲۳۴۵۶۷۸۹/0123456789/'
21

(またはGNU trtrではなくを使用)

ロケールを設定するen_US.utf8(または文字セットが属するロケールに良い)のために必要であるsedあなたの文字が設定認識します。

perl

$ echo "۲۱" |
  perl -CS -MUnicode::UCD=num -MUnicode::Normalize -lne 'print num(NFKD($_))'
21

を設定するLC_ALL必要があるので、すべてのユニコード文字も、そのように見なされsedますよね?
phk

@phk:はい、更新をご覧ください。
cuonglm

なぜすべてがsedスクリプトである必要があるのですか?trこの正確な目的のために発明しませんでしたか?
ケビン

3
@Kevin trそれがどこでも機能しない方法に関する他の回答を参照してください。また、バイトを処理するために最適化されているツールもあれば、文字を処理するために最適化されているツールもあることに注意してください。
phk

これはOS X 10.10.5 / GNU bash 4.3では機能しません。奇妙なことに、の明示的な設定を削除する必要がありLC_ALLます。LC_ALLまた、私の環境で設定されていない(しかしLANGに設定されていますen_GB.UTF-8)。上記のコードでは、「sed:1: "y / ۰۱۲۳۴۵۶۷۸۹ / ...":変換文字列は同じ長さではありません」というエラーが表示されます。
コンラッドルドルフ

15

Pythonのためにそこにあるunidecode。一般に、このような変換を扱うライブラリhttps://pypi.python.org/pypi/Unidecodeが

Python 2の場合:

>>> from unidecode import unidecode
>>> unidecode(u"۰۱۲۳۴۵۶۷۸۹")
'0123456789'

Python 3の場合:

>>> from unidecode import unidecode
>>> unidecode("۰۱۲۳۴۵۶۷۸۹")
'0123456789'

/programming//q/8087381/2261442のSOスレッドは関連している可能性があります。

/編集:ワンダーナウタがコメントで指摘したように、Unidecodeページで言及されているように、シェルバージョンもありますunidecode(上に/usr/local/bin/インストールされた場合pip)。

$ echo '۰۱۲۳۴۵۶۷۸۹' | unidecode
0123456789

2
unidecodeライブラリにunidecodeは、Python 3スニペットと同じことを行う(当然のことながら)というユーティリティも含まれています。ジャストはecho '۰۱۲۳۴۵۶۷۸۹' | unidecode動作するはずです。
さまようナウタ

@Wander-python-unidecodeのDebianパッケージにはユーティリティプログラムが含まれていないため、このようなプラットフォームでは長い形式が必要な場合があります(アップストリームからソースtarballで見つからなかったため、おそらくプログラムはあなたの分布?)
トビー・スペイト

@TobySpeightを使用しpipてインストールすると、そこにあります。
phk

@TobySpeightユーティリティはアップストリームのtarballにあります-Debianにunidecode/util.py含まれていないのは奇妙です。(編集:ああ、謎は解決しました。Debianパッケージは古く、ユーティリティよりも古いです。)
ワンダーナウタ

7

純粋なbashバージョン:

#!/bin/bash

number="$1"

number=${number//۱/1}
number=${number//۲/2}
number=${number//۳/3}
number=${number//۴/4}
number=${number//۵/5}
number=${number//۶/6}
number=${number//۷/7}
number=${number//۸/8}
number=${number//۹/9}
number=${number//۰/0}

echo "Result is $number"

私のGentooマシンでテストしましたが、動作します。

./convert ۱۳۲
Result is 132

変換する文字のリスト(0〜9)を指定すると、ループとして実行されます。

#!/bin/bash
conv() ( LC_ALL=en_US.UTF-8
         local n="$2"
         for ((i=0;i<${#1};i++)); do
              n=${n//"${1:i:1}"/"$i"}
         done
         printf '%s\n' "$n"
       )

conv "۰۱۲۳۴۵۶۷۸۹" "$1"

として使用されます:

$ convert ۱۳۲
132

を使用する別の(かなり過剰な)方法grep

#!/bin/bash

nums=$(echo "$1" | grep -o .)
result=()

for i in $nums
do
    case $i in
        ۱)
            result+=1
            ;;
        ۲)
            result+=2
            ;;
        ۳)
            result+=3
            ;;
        ۴)
            result+=4
            ;;
        ۵)
            result+=5
            ;;
        ۶)
            result+=6
            ;;
        ۷)
            result+=7
            ;;
        ۸)
            result+=8
            ;;
        ۹)
            result+=9
            ;;
        ۰)
            result+=0
            ;;
    esac
done
echo "Result is $result"

1
を除く、純粋なバッシュgrep。実際、私はその行を理解せず、なぜあなたがを設定しないのかを理解していませんresult=0$1ペルシア語以外の数字が含まれている場合、過度に慎重になっていますか?
クサラナナンダ

@Kusalanandaその行は、ペルシア語の数字をnumsに読み込みます。ループ可能にします。
coffeMug

1
テン簡単な置換は...速くされているだろうnumber=${number//۱/1}などと、避けるだろうechogrep
クサラナナンダ

1
@Kusalanandaニース。変更しました。今、それは純粋なバッシュです!;-)
coffeMug

@coffeMug:132 132全く123ではない:D
بارپابابا

3

これiconvを理解できないように思えるので、次の呼び出しはtrユーティリティを使用することです。

$ echo "۲۱" | tr '۰۱۲۳۴۵۶۷۸۹' '0123456789'
21

tr 文字セットを別の文字セットに変換するため、ペルシア語の数字のセットをラテン語の数字のセットに変換するように指示します。

編集:ユーザー@cuonglmが指摘しているように。これは、非GNUを必要としtr、たとえば、trMac上で、それはまた、その必要が$LC_CTYPEに設定されていますen_US.UTF-8


2
マルチバイト文字をサポートしていないGNU trでは動作しないことに注意してください。
クオンルム

1
あら 愚かなGNU。;-)
クサラナナンダ

また、のように、Unicodeをサポートするロケールにロケールを設定する必要がありますen_US.utf8
クオンルム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.