如何将 UTF-8 中的波斯数字转换为 ASCII 中的欧洲数字?

Bab*_*aba 16 bash unicode conversion

在波斯数字中,??????????相当于0123456789在欧洲数字中。

如何将波斯数字( in UTF-8)转换为 ASCII?

例如,我想??成为21.

cuo*_*glm 27

由于它是一组固定的数字,您可以手动完成:

$ echo ?? | LC_ALL=en_US.UTF-8 sed -e 'y/??????????/0123456789/'
21
Run Code Online (Sandbox Code Playgroud)

(或使用tr,但尚未使用GNU tr

需要将您的语言环境设置为en_US.utf8(或更好地设置为字符集所属的语言环境)sed才能识别您的字符集。

perl

$ echo "??" |
  perl -CS -MUnicode::UCD=num -MUnicode::Normalize -lne 'print num(NFKD($_))'
21
Run Code Online (Sandbox Code Playgroud)

  • @Kevin 看到另一个涉及 `tr` 的答案,它是如何在任何地方都不起作用的。还请记住,一些工具针对处理字节进行了优化,而其他工具针对处理字符进行了优化,使用 Unicode(尤其是 UTF-8)会产生巨大的差异。 (3认同)

phk*_*phk 15

对于 Python,有unidecode一个处理此类转换的库:https : //pypi.python.org/pypi/Unidecode

在 Python 2 中:

>>> from unidecode import unidecode
>>> unidecode(u"??????????")
'0123456789'
Run Code Online (Sandbox Code Playgroud)

在 Python 3 中:

>>> from unidecode import unidecode
>>> unidecode("??????????")
'0123456789'
Run Code Online (Sandbox Code Playgroud)

/sf/ask/566116701/ 上的 SO 线程可能与此相关。

/ 编辑:正如 Wander Nauta 在评论中指出的,正如在 Unidecode 页面上提到的,还有一个 shell 版本unidecode/usr/local/bin/如果安装在下面pip):

$ echo '??????????' | unidecode
0123456789
Run Code Online (Sandbox Code Playgroud)

  • unidecode 库还提供了一个名为(不出所料)`unidecode` 的实用程序,它的作用与您的 Python 3 代码段相同。只是`echo '۰۱۲۳۴۵۶۷۸۹' | unidecode` 应该可以工作。 (2认同)

cof*_*Mug 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"
Run Code Online (Sandbox Code Playgroud)

已经在我的 Gentoo 机器上测试过,它可以工作。

./convert ???
Result is 132
Run Code Online (Sandbox Code Playgroud)

给定要转换的字符列表(从 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"
Run Code Online (Sandbox Code Playgroud)

并用作:

$ convert ???
132
Run Code Online (Sandbox Code Playgroud)

另一种(相当矫枉过正)方式使用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"
Run Code Online (Sandbox Code Playgroud)


小智 6

我们可以利用波斯数字的 UNICODE 代码点是连续的并且从 0 到 9 排序的事实:

$ printf '%b' '\U06F'{0..9}
??????????
Run Code Online (Sandbox Code Playgroud)

这意味着最后一个十六进制数字是十进制值:

$ echo $(( $(printf '%d' "'?") & 0xF ))
2
Run Code Online (Sandbox Code Playgroud)

这使得这个简单的循环成为一个转换工具:

#!/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
Run Code Online (Sandbox Code Playgroud)

将其用作:

$ sefr.sh ??????????
0123456789

$ sefr.sh ???
201

$ sefr.sh ??
21
Run Code Online (Sandbox Code Playgroud)

请注意,此代码还可以转换阿拉伯数字和拉丁数字(即使混合):

$ sefr.sh ?4??5??6??7??8??9?
444555666777888999

$ sefr.sh ??0??7??3????
4700671335667
Run Code Online (Sandbox Code Playgroud)