在波斯数字中,۰۱۲۳۴۵۶۷۸۹
等同0123456789
于欧洲数字。
如何转换波斯数字( UTF-8
)为ASCII?
例如,我想۲۱
成为21
。
iconv
只是在这里以不同的编码映射字符,但是这些字符(ASCII字符中没有等效的阿拉伯阿拉伯数字),您可以将它们转换为足够类似的字符,但仅是单向的。
iconv
和不该做什么。我希望使用//TRANSLIT
可以有所帮助,但没有帮助。
在波斯数字中,۰۱۲۳۴۵۶۷۸۹
等同0123456789
于欧洲数字。
如何转换波斯数字( UTF-8
)为ASCII?
例如,我想۲۱
成为21
。
iconv
只是在这里以不同的编码映射字符,但是这些字符(ASCII字符中没有等效的阿拉伯阿拉伯数字),您可以将它们转换为足够类似的字符,但仅是单向的。
iconv
和不该做什么。我希望使用//TRANSLIT
可以有所帮助,但没有帮助。
Answers:
我们可以利用以下事实:波斯数字的UNICODE代码点是连续的,并且从0到9进行排序:
$ printf '%b' '\U06F'{0..9}
۰۱۲۳۴۵۶۷۸۹
这意味着最后一个十六进制数字是十进制值:
$ 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将给出UNICODE代码点"
。在此链接之前稍微搜索一下文本“如果前导字符是单引号还是双引号”
由于它是一组固定的数字,因此您可以手动进行:
$ 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
LC_ALL
需要设置,以便每个单个Unicode字符也将被视为sed
,对吧?
tr
为此目的而发明的吗?
tr
该答案涉及它并非在所有地方都起作用。还请记住,某些工具针对处理字节进行了优化,而其他工具则针对处理字符进行了优化,使用Unicode(尤其是UTF-8)会产生很大的不同。
LC_ALL
。LC_ALL
也未在我的环境LANG
中设置(但设置为en_GB.UTF-8
)。使用上面的代码,我得到错误“ sed:1:“ y / ۰۱۲۳۴۵۶۷۸۹ / ...”:转换字符串的长度不同”。
对于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线程可能相关。
/ edit:正如Wander Nauta在评论中指出的那样,并且在Unidecode页面上提到的,还有一个shell版本unidecode
(/usr/local/bin/
如果安装在,则在下面pip
):
$ echo '۰۱۲۳۴۵۶۷۸۹' | unidecode
0123456789
unidecode
,它与您的Python 3代码段相同。只是echo '۰۱۲۳۴۵۶۷۸۹' | unidecode
应该工作。
pip
它安装,请在那里。
unidecode/util.py
-奇怪的是Debian不包含它。(编辑:啊,谜团解决了。Debian软件包已经过时并且比实用程序还旧。)
一个纯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"
grep
。实际上,我不理解该行,也不理解您为什么不设置result=0
。如果$1
包含波斯数字以外的内容,您是否过于谨慎?
number=${number//۱/1}
等等,并且可以避免使用echo
and grep
。
由于iconv
似乎无法理解这一点,因此下一个调用端口将是使用该tr
实用程序:
$ echo "۲۱" | tr '۰۱۲۳۴۵۶۷۸۹' '0123456789'
21
tr
将一组字符转换为另一组字符,因此我们简单地告诉它将波斯数字组转换为拉丁数字组。
编辑:作为用户@cuonglm指出。这要求使用非GNU tr
(例如tr
在Mac上),并且还要求将$LC_CTYPE
其设置为en_US.UTF-8
。
en_US.utf8
。
echo "۰۱۲۳۴۵۶۷۸۹" | iconv -f UTF-8 -t ascii//TRANSLIT