UTF-8의 페르시아 숫자를 ASCII의 유럽 숫자로 어떻게 변환 할 수 있습니까? ۰۱۲۳۴۵۶۷۸۹와 같습니다 0123456789. 페르시아

페르시아 숫자 에서 유럽 숫자 ۰۱۲۳۴۵۶۷۸۹와 같습니다 0123456789.

페르시아 숫자 (in UTF-8)를 ASCII 로 변환하려면 어떻게 해야합니까?

예를 들어, 내가 원하는 ۲۱되기 위해 21.



답변

우리는 페르시아 숫자의 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


답변

고정 된 숫자 세트이므로 직접 할 수 있습니다.

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

(또는 사용 tr하지만, 하지 GNU의 TR 아직)

에 로케일 설정 en_US.utf8(또는 문자 세트가 속해있는 로케일 이상)에 필요한 sed캐릭터 설정 인식.

perl:

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


답변

파이썬 들어있다 unidecode: 일반적으로 이러한 변환을 처리하는 라이브러리 https://pypi.python.org/pypi/Unidecode은 .

파이썬 2에서 :

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

파이썬 3에서 :

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

/programming//q/8087381/2261442 의 SO 스레드 가 관련 될 수 있습니다.

/ edit : Wander Nauta가 주석에서 지적했듯이 Unidecode 페이지에서 언급했듯이 셸 버전도 있습니다 unidecode( /usr/local/bin/설치된 경우 아래 pip).

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


답변

순수한 배쉬 버전 :

#!/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"

내 젠투 머신에서 테스트했는데 작동합니다.

./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"


답변

이 문제를 iconv해결할 수 없기 때문에 다음 호출 포트는 tr유틸리티 를 사용하는 것입니다 .

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

tr 한 문자 집합을 다른 문자 집합으로 변환하므로 단순히 Farsi 숫자 집합을 라틴 숫자 집합으로 변환하도록 지시합니다.

편집 : @cuonglm 사용자가 지적한대로. 이를 위해서는 Mac과 tr같은 비 GNU 가 tr필요하고 $LC_CTYPE로 설정되어 있어야합니다 en_US.UTF-8.


답변