首页 > 解决方案 > 正确处理土耳其语大写和小写,需要修改/覆盖内置函数?

问题描述

我正在处理多语言文本数据,其中包括使用西里尔字母和土耳其语的俄语。我基本上必须比较两个文件中my_filecheck_file单词,如果my_file可以在 中找到单词,check_file则将它们写入输出文件,保留两个输入文件中关于这些单词的元信息。

有些单词是小写的,而其他单词是大写的,所以我必须将所有单词都小写来比较它们。由于我使用 Python 3.6.5 而 Python 3 默认使用 unicode,因此它会处理小写字母,然后再将西里尔字母的单词正确大写。然而,对于土耳其语,有些字母处理不正确。大写'İ'应该对应小写'i',大写'I'应该对应小写'ı',小写'i'应该对应大写'İ',如果我在控制台中键入以下内容,情况并非如此:

>>> print('İ'.lower())
i̇  # somewhat not rendered correctly, corresponds to unicode 'i\u0307'
>>> print('I'.lower())
i
>>> print('i'.upper())
I

我正在执行以下操作(简化示例代码):

# python my_file check_file language

import sys

language = sys.argv[3]

# code to get the files as lists

my_file_list = [['ıspanak', 'N'], ['ısır', 'N'], ['acık', 'V']]
check_file_list = [['109', 'Ispanak', 'food_drink'], ['470', 'Isır', 'action_words'], [409, 'Acık', 'action_words']]

# get the lists as dict
my_dict = {}
check_dict = {}

for l in my_file_list:
    word = l[0].lower()
    pos = l[1]
    my_dict[word] = pos

for l in check_file_list:
    word_id = l[0]
    word = l[1].lower()
    word_cat = l[2]
    check_dict[word] = [word_id, word_cat]

# compare the two dicts
for word, pos in my_dict.items():
    if word in check_dict:
        word_id = check_dict[word][0]
        word_cat = check_dict[word][1]
        print(word, pos, word_id, word_cat)

这只给了我一个结果,但它应该给我三个词作为结果:

acık V 409 action_words

到目前为止,我根据这个问题做了什么:

  1. 阅读建议使用PyICU的已接受答案,但我希望我的代码无需安装即可使用,所以我没有实现它。
  2. 尝试import localelocale.setlocale(locale.LC_ALL, 'tr_TR.UTF-8')如问题中提到的那样,但它没有改变任何东西。
  3. 如第二个答案中所述,实现两个功能turkish_lower(self)turkish_upper(self)三个有问题的字母,这似乎是唯一的解决方案:

    def turkish_lower(self):
        self = re.sub(r'İ', 'i', self)
        self = re.sub(r'I', 'ı', self)
        self = self.lower()
        return self
    
    def turkish_upper(self):
        self = re.sub(r'i', 'İ', self)
        self = self.upper()
        return self
    

但是我怎样才能使用这两个功能而不必if language == 'Turkish'每次都检查呢?lower()我应该覆盖内置函数upper()吗?如果是,那么pythonic的做法是什么?我应该为我正在使用的各种语言实现类并覆盖土耳其语类中的内置函数吗?

标签: pythonpython-3.xbuilt-incyrillicturkish

解决方案


您可以创建一个简单的“语言感知”字符串,将其子类str化并进行正确的大写和小写,例如:

class LanguageAwareStr(str):
    lang = None


class RussianStr(LanguageAwareStr):
    lang = 'ru'


class TurkishStr(LanguageAwareStr):
    lang = 'tr'

    _case_lookup_upper = {'İ': 'i', 'I': 'ı'}  # lookup uppercase letters
    _case_lookup_lower = {v: k for (k, v) in _case_lookup_upper.items()}

    # here we override the lower() and upper() methods
    def lower(self):
        chars = [self._case_lookup_upper.get(c, c) for c in self]
        result = ''.join(chars).lower()
        cls = type(self)  # so we return a TurkishStr result
        return cls(result)

    def upper(self):
        chars = [self._case_lookup_lower.get(c, c) for c in self]
        result = ''.join(chars).upper()
        cls = type(self)  # so we return a TurkishStr result
        return cls(result)

然后当你读取一个字符串,知道它是什么语言时,你将它包装在适当的 LanguageAwareStr 子类中,然后定期使用它:


from langaware import RussianStr, TurkishStr
if language == 'turkish':
    LangStr = TurkishStr  # can also create a dict to lookup the correct class

然后,当您阅读语言字符串时,您只需将它们包装在对以下的调用中LangStr()

for l in my_file_list:
    word = LangStr(l[0]).lower()
    pos = l[1]
    my_dict[word] = pos

for l in check_file_list:
    word_id = l[0]
    word = LangStr(l[1]).lower()
    word_cat = l[2]
    check_dict[word] = [word_id, word_cat]

推荐阅读