如何检查Python unicode字符串是否包含非西方字母?

时间:2010-06-22 15:13:36

标签: python django unicode

我有一个Python Unicode字符串。我想确保它只包含罗马字母(A到Z)中的字母,以及欧洲字母表中常见的字母,例如ß,ü,ø,é,à和î。 应包含其他字母(中文,日文,韩文,阿拉伯文,西里尔文,希伯来文等)中的字符。这样做的最佳方式是什么?

目前我正在使用这段代码,但我不知道这是否是最佳方式:

def only_roman_chars(s):
    try:
        s.encode("iso-8859-1")
        return True
    except UnicodeDecodeError:
        return False

(我正在使用Python 2.5。我也在Django中这样做,所以如果Django框架碰巧有办法处理这样的字符串,我可以使用该功能 - 我没有遇到过这样的事情,但是。)

8 个答案:

答案 0 :(得分:31)

import unicodedata as ud

latin_letters= {}

def is_latin(uchr):
    try: return latin_letters[uchr]
    except KeyError:
         return latin_letters.setdefault(uchr, 'LATIN' in ud.name(uchr))

def only_roman_chars(unistr):
    return all(is_latin(uchr)
           for uchr in unistr
           if uchr.isalpha()) # isalpha suggested by John Machin

>>> only_roman_chars(u"ελληνικά means greek")
False
>>> only_roman_chars(u"frappé")
True
>>> only_roman_chars(u"hôtel lœwe")
True
>>> only_roman_chars(u"123 ångstrom ð áß")
True
>>> only_roman_chars(u"russian: гага")
False

答案 1 :(得分:26)

@tzot的最佳答案很棒,但IMO应该有一个适用于所有脚本的库。 So, I made one(严重依据这个答案)。

pip install alphabet-detector

然后直接使用它:

from alphabet_detector import AlphabetDetector
ad = AlphabetDetector()

ad.only_alphabet_chars(u"ελληνικά means greek", "LATIN") #False
ad.only_alphabet_chars(u"ελληνικά", "GREEK") #True
ad.only_alphabet_chars(u'سماوي يدور', 'ARABIC')
ad.only_alphabet_chars(u'שלום', 'HEBREW')
ad.only_alphabet_chars(u"frappé", "LATIN") #True
ad.only_alphabet_chars(u"hôtel lœwe 67", "LATIN") #True
ad.only_alphabet_chars(u"det forårsaker første", "LATIN") #True
ad.only_alphabet_chars(u"Cyrillic and кириллический", "LATIN") #False
ad.only_alphabet_chars(u"кириллический", "CYRILLIC") #True

此外,主要语言的一些便利方法:

ad.is_cyrillic(u"Поиск") #True  
ad.is_latin(u"howdy") #True
ad.is_cjk(u"hi") #False
ad.is_cjk(u'汉字') #True

答案 2 :(得分:1)

对于你说你想做的事,你的方法是正确的。如果您在Windows上运行,我建议您使用cp1252而不是iso-8859-1。您也可以允许cp1250 - 这将取消东欧国家,如波兰,捷克共和国,斯洛伐克,罗马尼亚,斯洛文尼亚,匈牙利,克罗地亚等,其中字母表是拉丁语。其他cp125x将包括土耳其语和马耳他语......

您可能还想考虑从西里尔语到拉丁语的转录;据我所知,有几个系统,其中一个系统可能得到万国邮联(万国邮政联盟)的认可。

我对你的评论有点兴趣“我们的运输部门不想用例如中文地址填写标签”......三个问题:(1)你的意思是“国家X的地址“或”用X-ese字符写的地址“(2)你的系统打印标签会不会更好? (3)如果订单未通过测试,订单会如何发货?

答案 3 :(得分:1)

检查ISO-8559-1会错过合理的西方字符,如'œ'和'€'。解决方案取决于您如何定义“西方”,以及您希望如何处理非字母。这是一种方法:

import unicodedata

def is_permitted_char(char):
    cat = unicodedata.category(char)[0]
    if cat == 'L': # Letter
        return 'LATIN' in unicodedata.name(char, '').split()
    elif cat == 'N': # Number
        # Only DIGIT ZERO - DIGIT NINE are allowed
        return '0' <= char <= '9'
    elif cat in ('S', 'P', 'Z'): # Symbol, Punctuation, or Space
        return True
    else:
        return False

def is_valid(text):
    return all(is_permitted_char(c) for c in text)

答案 4 :(得分:1)

标准string软件包包含所有Latin个字母numberssymbols。您可以从文本中删除这些值,如果还有剩余,则不是拉丁字符。我做到了:

In [1]: from string import printable                                                                                                                                                                           

In [2]: def is_latin(text): 
   ...:     return not bool(set(text) - set(printable)) 
   ...:                                                                                                                                                                                                        

In [3]: is_latin('Hradec Králové District,,Czech Republic,')                                                                                                                                                   
Out[3]: False

In [4]: is_latin('Hradec Krlov District,,Czech Republic,')                                                                                                                                                     
Out[4]: True

我无法检查所有非拉丁字符,如果有人可以这样做,请告诉我。谢谢。

答案 5 :(得分:0)

检查django.template.defaultfilters.slugify

中的代码
import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')

是您正在寻找的,然后您可以将结果字符串与原始

进行比较

答案 6 :(得分:0)

如果你是django用户,也许会这样做?

from django.template.defaultfilters import slugify 

def justroman(s):
  return len(slugify(s)) == len(s)

答案 7 :(得分:0)

使用内置的 unicodedata 库简单地回答 tzot,这似乎对我有用:

import unicodedata as ud

def is_latin(word):
    return all(['LATIN' in ud.name(c) for c in word])