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

如何检查Python unicode字符串是否包含非西方字母?,python,django,unicode,Python,Django,Unicode,我有一个Python Unicode字符串。我想确保它只包含罗马字母表中的字母(A到Z),以及欧洲字母表中常见的字母,如ß、ü、ø、é、á和î。它不应包含来自其他字母表(汉语、日语、韩语、阿拉伯语、西里尔语、希伯来语等)的字符。做这件事最好的方法是什么 目前我正在使用这段代码,但我不知道这是否是最好的方法: def only_roman_chars(s): try: s.encode("iso-8859-1") return True except

我有一个Python Unicode字符串。我想确保它只包含罗马字母表中的字母(A到Z),以及欧洲字母表中常见的字母,如ß、ü、ø、é、á和î。它不应包含来自其他字母表(汉语、日语、韩语、阿拉伯语、西里尔语、希伯来语等)的字符。做这件事最好的方法是什么

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

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

(我正在使用Python2.5。我也在Django中这样做,因此如果Django框架碰巧有一种处理此类字符串的方法,我可以使用该功能——但是我没有遇到类似的情况。)

检查
Django.template.defaultfilters.slugify中的代码

import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')

就是您要寻找的,然后您可以将结果字符串与原始字符串进行比较

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

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


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

检查ISO-8559-1将丢失合理的西文字符,如“œ”和“欧元”。解决方案取决于您如何定义“Western”,以及您希望如何处理非字母。这里有一种方法:

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)
导入Unicode数据
def是允许的字符(字符):
cat=unicodedata.category(char)[0]
如果cat='L':#字母
返回Unicode数据中的“拉丁语”。名称(字符“”).split()
elif cat=='N':#编号
#只允许数字0-数字9

返回“0”如果您是django用户,这是否可以

from django.template.defaultfilters import slugify 

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

@tzot对此的最佳答案非常好,但在我看来,应该有一个适用于所有脚本的库。(主要基于这个答案)

然后直接使用它:

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

标准的
字符串
包包含所有
拉丁字母
数字
符号
。您可以从文本中删除这些值,如果还有剩余内容,则不是拉丁字符。我做到了:

[1]中的
:从字符串导入可打印
在[2]中,def是拉丁语(文本):
…:返回非布尔值(集合(文本)-集合(可打印))
...:                                                                                                                                                                                                        
在[3]中:是拉丁语(“捷克共和国赫拉代克·克拉洛夫区”)
Out[3]:False
在[4]中:是拉丁语(“捷克共和国赫拉德克洛夫区”)
Out[4]:正确

我没有办法检查所有非拉丁字符,如果有人能做到,请告诉我。谢谢。

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

将Unicode数据导入为ud
def是拉丁语(单词):
返回全部(['LATIN'在ud.name(c)中表示word中的c])

过滤这些字符的目标是什么?我想不出一个好的理由来这样做,这不是代码库中其他地方出错的症状。过滤邮件地址。我们的运输部门不想在标签上填上中文地址。那你就不能用国家来代替吗?(否则,有趣的问题+1)不是真的。例如,有人可以选择“China”并仍然输入适当的地址。我不想将所有内容都变成小写或将空格转换为破折号,只需检查字符串是否包含不需要的字符。我改变了问题,以避免使用“过滤器”一词。(1)返回unicodedata.name(char),).startswith('LATIN')
应该足够了(2)记忆函数结果可能是个好主意,可以通过在备忘录中预加载通常的可疑点[-a-Za-z0-9,./')等来改进。(3)符号/标点比较宽(4)类别空间是否应替换为“\x20”?(1)后者(以X-ese字符书写的地址)。(2) 也许吧。现在,它没有。表单是web应用程序的一部分;数据被完全分流到另一个系统,该系统处理订单管理等。(3)表单未通过验证并提示用户输入适当的地址。我建议无论您是否在windows上,都不要使用cp125x,因为它与适当的标准化字符集和编码不兼容。它将合法的西文字符放在Unicode和ISO中保留的“C1”控制字符范围内。古老的“CP”代码页编码是有限字符集空间的一种解决方法,在所有现代代码中都应该避免使用。@StephenP:OP已经有Unicode字符串;我建议他认为角色的可能性很强。
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