Как я могу проверить, содержит ли строка Unicode Python не западные буквы? - PullRequest
23 голосов
/ 22 июня 2010

У меня есть строка 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 может обрабатывать такие строки, я могу использовать эту функциональность - я не встречал ничего подобного, однако.)

Ответы [ 6 ]

33 голосов
/ 22 июля 2010
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
27 голосов
/ 03 марта 2015

Лучший ответ на этот вопрос от @tzot великолепен, но IMO должна действительно быть библиотека для этого, которая работает для всех сценариев. Итак, я сделал один (в значительной степени основываясь на этом ответе).

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
1 голос
/ 23 июня 2010

При проверке 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)
1 голос
/ 23 июня 2010

Для того, что вы говорите, вы хотите сделать, ваш подход является правильным. Если вы работаете в Windows, я бы предложил использовать cp1252 вместо iso-8859-1. Вы можете также разрешить cp1250 - это подберет страны Восточной Европы, такие как Польша, Чехия, Словакия, Румыния, Словения, Венгрия, Хорватия и т. Д., Где алфавит основан на латинице. Другие cp125x будут включать турецкий и мальтийский ...

Вы также можете рассмотреть транскрипцию с кириллицы на латиницу; Насколько я знаю, существует несколько систем, одна из которых может быть одобрена ВПС (Всемирный почтовый союз).

Меня немного заинтриговал ваш комментарий: «Наш отдел доставки не хочет заполнять этикетки, например, с китайскими адресами» ... три вопроса: (1) вы имеете в виду "адреса в стране X "или" адреса, написанные символами X-ese "(2) не лучше ли для вашей системы печатать этикетки? (3) как доставляется заказ, если он не прошел тест?

0 голосов
/ 28 июня 2010

Может быть, это подойдет, если вы пользователь django?

from django.template.defaultfilters import slugify 

def justroman(s):
  return len(slugify(s)) == len(s)
0 голосов
/ 22 июня 2010

проверьте код в django.template.defaultfilters.slugify

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

- это то, что вы ищете, затем вы можете сравнить полученную строку с оригинальной

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...