String.maketrans 用于英语和波斯语数字



我有一个这样的函数:

persian_numbers = '۱۲۳۴۵۶۷۸۹۰'
english_numbers = '1234567890'
arabic_numbers  = '١٢٣٤٥٦٧٨٩٠'
english_trans   = string.maketrans(english_numbers, persian_numbers)
arabic_trans    = string.maketrans(arabic_numbers, persian_numbers)
text.translate(english_trans)
text.translate(arabic_trans)

我希望它将所有阿拉伯语和英语数字翻译成波斯语。但是Python说:

english_translate = string.maketrans(english_numbers, persian_numbers)
ValueError: maketrans arguments must have same length

我尝试使用 Unicode utf-8 对字符串进行编码,但我总是遇到一些错误!有时问题是阿拉伯字符串!您知道这项工作的更好解决方案吗?

编辑:

似乎问题是 ASCII 中的 Unicode 字符长度。像"۱"这样的阿拉伯数字是两个字符 - 我用ord()找到。长度问题从这里开始:-(

参见将所有字符串转换为 UTF8 的 unidecode 库。在不同语言的数字输入的情况下非常有用。

在 Python 2 中:

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

在 Python 3 中:

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

Unicode 对象可以将这些数字(阿拉伯语和波斯语)解释为实际数字 -无需使用字符替换来翻译它们。

编辑-我想出了一种方法来使用 Python2 正则表达式进行替换:

# coding: utf-8
import re
# Attention: while the characters for the strings bellow are 
# dislplayed indentically, inside they are represented
# by distinct unicode codepoints
persian_numbers = u'۱۲۳۴۵۶۷۸۹۰'
arabic_numbers  = u'١٢٣٤٥٦٧٨٩٠'
english_numbers = u'1234567890'

persian_regexp = u"(%s)" %  u"|".join(persian_numbers)
arabic_regexp = u"(%s)" % u"|".join(arabic_numbers)
def _sub(match_object, digits):
    return english_numbers[digits.find(match_object.group(0))]
def _sub_arabic(match_object):
    return _sub(match_object, arabic_numbers)
def _sub_persian(match_object):
    return _sub(match_object, persian_numbers)

def replace_arabic(text):
    return re.sub(arabic_regexp, _sub_arabic, text)
def replace_persian(text):
    return re.sub(arabic_regexp, _sub_persian, text)

尝试将"text"参数本身必须是 unicode。

(此代码也可以缩短通过使用 lambda 并将一些表达式组合在一行中,但这样做没有意义,但会失去可读性)

它应该对你有用,但请阅读我发布的原始答案

-- 原答案

因此,如果您将变量实例化为 unicode(在引号字符前面加上 u),则在 Python 中可以正确理解它们:

>>> persian_numbers = u'۱۲۳۴۵۶۷۸۹۰'
>>> english_numbers = u'1234567890'
>>> arabic_numbers  = u'١٢٣٤٥٦٧٨٩٠'
>>> 
>>> print int(persian_numbers)
1234567890
>>> print int(english_numbers)
1234567890
>>> print int(arabic_numbers)
1234567890
>>> persian_numbers.isdigit()
True
>>> 

顺便说一下,unicode 对象不存在 "maketrans" 方法(在 Python2 中 - 请参阅注释)。

了解 unicode 的基础知识非常重要 - 对于每个人来说,即使是那些编写纯英语程序的人,他们认为他们永远不会处理 26 个拉丁字母中的任何字符。在编写将处理不同字符的代码时,这一点至关重要 - 除非偶然知道自己在做什么,否则程序不可能在你不知道自己在做什么的情况下工作。

一篇非常好的文章 http://www.joelonsoftware.com/articles/Unicode.html - 请立即阅读。在阅读它时,你可以记住,Python 允许使用 unicode 对象的"编码"方法将 unicode 字符转换为任何"物理"编码的字符串。

>>> arabic_numbers  = u'١٢٣٤٥٦٧٨٩٠'
>>> len(arabic_numbers)
10
>>> enc_arabic = arabic_numbers.encode("utf-8")
>>> print enc_arabic
١٢٣٤٥٦٧٨٩٠
>>> len(enc_arabic)
20
>>> int(enc_arabic)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'xd9xa1xd9xa2xd9xa3xd9xa4xd9xa5xd9xa6xd9xa7xd9xa8xd9xa9xd9xa0'

因此,字符在编码时失去了作为"单个实体"和数字的意义 - 编码对象(Python 2.x 中的 str 类型)只是字节的 strrng - 尽管如此,当将这些字符发送到程序的任何输出时,仍然需要这些字符 - 无论是控制台、GUI 窗口、数据库、html 代码等......

您可以使用波斯语工具包:

例子:

>>> from persiantools import digits
>>> digits.en_to_fa("0987654321")
'۰۹۸۷۶۵۴۳۲۱'
>>> digits.ar_to_fa("٠٩٨٧٦٥٤٣٢١")   # or digits.ar_to_fa(u"٠٩٨٧٦٥٤٣٢١")
'۰۹۸۷۶۵۴۳۲۱'
unidecode将所有

字符从波斯语转换为英语,如果您只想更改数字,请遵循以下操作:

在python3中,您可以使用此代码转换任何波斯语|阿拉伯数字到英文数字,同时保持其他字符不变:

intab='۱۲۳۴۵۶۷۸۹۰١٢٣٤٥٦٧٨٩٠'
outtab='12345678901234567890'
translation_table = str.maketrans(intab, outtab)
output_text = input_text.translate(translation_table)

使用 Unicode 字符串:

persian_numbers = u'۱۲۳۴۵۶۷۸۹۰'
english_numbers = u'1234567890'
arabic_numbers  = u'١٢٣٤٥٦٧٨٩٠'

并确保 Python 文件的编码正确。

有了这个,你可以很容易地做到这一点:

def p2e(persiannumber):
    
    number={
        '0':'۰',
        '1':'۱',
        '2':'۲',
        '3':'۳',
        '4':'۴',
        '5':'۵',
        '6':'۶',
        '7':'۷',
        '8':'۸',
        '9':'۹',
   }
    for i,j in number.items():
        persiannumber=persiannumber.replace(j,i)
        
    return persiannumber

这是用法:

print(p2e('۳۱۹۶'))
#returns 3196

在Python 3中,最简单的方法是:

str(int('۱۲۳'))
#123

但是如果数字以 0 开头,则有问题。

所以我们可以使用zip()函数:

for i, j in zip('1234567890', '۱۲۳۴۵۶۷۸۹۰'):
    number.replace(i, j)
def persian_number(persiannumber):
    
    number={
        '0':'۰',
        '1':'۱',
        '2':'۲',
        '3':'۳',
        '4':'۴',
        '5':'۵',
        '6':'۶',
        '7':'۷',
        '8':'۸',
        '9':'۹',
   }
    for i,j in number.items():
        persiannumber=time2str.replace(i,j)
        
    return time2str

波斯数字必须是字符串

最新更新