如何在 python 中创建泰米尔语注音键盘输入?

How to Create a Tamil Phonetic keyboard inputs in python?

我的目标: 使用字典键映射创建泰米尔语注音键盘。 我的挣扎: 如何用值替换我的键并将该值设置到我的文本框。 例如: 如果我在 textbox1 中按 "K",那么我的 textbox1.text 将换成淡米尔文字母 "க்",如果我按 "Ku" 那么 textbox1.text 将被泰米尔文字母 "கு",,如果我按 "kuu",那么 textbox1.text 将被泰米尔字母 "கூ" 取代 然后如果我按 "m" 然后泰米尔字母 "ம்" 将被添加到前一个字母 "கூ" 现在 textbox1.text 变成 "கூம்"

import sys

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

tamil_dict = {"a":{'a':'அ','aa':'ஆ'},
              "k":{'k':'க்','ka':'க','kaa':'கா','ki':'கி','kii':'கீ','ku':'கு','kuu':'கூ'},
              "m":{'m':'ம்','ma':'ம','maa':'மா','mi':'மி','mii':'மீ','mu':'மு','muu':'மூ'},
              "i":{"i":"இ"},
              "e":"ஈ "}


class Keyboard_Dict(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Tamil InPut ")

        self.tbox1 = QLineEdit()
        self.tbox1.setFont(QFont('Arial Unicode MS', 10, QFont.Bold))
        self.tbox1.textChanged.connect(self.func_textbox_textchanged)

        self.tbox2 = QLineEdit()
        self.tbox2.setFont(QFont('Arial Unicode MS', 10, QFont.Bold))

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.tbox1)
        self.vbox.addWidget(self.tbox2)
        self.setLayout(self.vbox)

        self.process_txt_temp_letter = ""
        self.process_txt_temp_position = 0
        self.process_letter_found = False
        self.process_letter_temp = False
        self.processed_text =""
    def func_textbox_textchanged(self,txt):
        self.txt_len = len(self.tbox1.text())
        if self.txt_len >= 1:
            self.process_txt_position = self.txt_len-1
            self.process_text_letter = (txt[self.process_txt_position])


            if self.process_letter_found == False:
                if (txt[self.txt_len-1]) in tamil_dict:
                    self.process_letter_found = True
                    self.process_txt_temp_position = (self.txt_len-1)
                    self.process_txt_temp_letter = (txt[self.txt_len-1])
                    self.process_letter_temp = True

            if self.process_letter_temp == True :
                if (txt[self.process_txt_temp_position:]) in tamil_dict[self.process_txt_temp_letter]:
                    self.processed_text =  tamil_dict[self.process_txt_temp_letter][txt[self.process_txt_temp_position:]]
                    print(self.processed_text)
                    # print("jjjjjjjjj",tamil_dict[self.process_txt_temp_letter][txt[self.process_txt_temp_position:]])

                elif (txt[self.process_txt_temp_position:]) not in tamil_dict[self.process_txt_temp_letter]:
                    self.process_txt_temp_position = self.txt_len - 1
                    self.process_txt_temp_letter = (txt[self.process_txt_temp_position])

                    if self.process_txt_temp_letter not in tamil_dict:
                        self.process_letter_temp = False
                        self.process_letter_found = False
                    else:
                        self.processed_text = tamil_dict[self.process_txt_temp_letter][txt[self.process_txt_temp_position:]]
                        print(self.processed_text)
                        # print("ffffff", tamil_dict[self.process_txt_temp_letter][txt[self.process_txt_temp_position:]])
        self.tbox2.setText(self.processed_text)





def main():
    app = QApplication(sys.argv)

    mainscreen = Keyboard_Dict()
    app.setStyle("Fusion")
    mainscreen.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

更新:1 我有一个键映射如下:

      *Main character/processed first character : "k"* 
        k     : "Apple"
        ka    : "Bannana"
        kaa   : "Citrus:
        ki    : "Orange"
        kii   : "Pine" 
        *Main character/processed first character : "M"* 
         m     : "is" 
         ma    : "more"
         maa   : "taste"
 *Main character/processed first character : "i"* 
         i     : "world"
         ii    : "earth"

tamil_dict ={"k":{"k":"apple","ka":"bannana","kaa":"citrus","ki":"orange","kii":"pine"},
             "m":{"m":"is","ma":"more","maa":"taste"},
             "i":{"i":"world","ii":"earth"}
            }


     

在我的 textbox.text 中,我的第一个字符是 "A",在字典中找不到,因此不需要处理该字符并按原样显示。

在我的 textbox.text 中,我的第二个输入词是 "k",它可以在我的词典中找到,也可以在 "k" 是主词。现在我处理的单词是 "A"+"k",我的文本框被替换如下,"A" + "Apple" = AApple

在我的textbox.text中,我的第三个字符是"a",现在我处理的单词是"ka",它在字典中找到。所以替换为等效值“Banana”。现在我处理的单词是 "A"+"ka",现在我的 textbox.text 如下:"A"+"banana" = Abanana.

在我的 textbox.text 中,我的第四个字符是 "a",我处理后的单词变成了 "Kaa" 它的等价物值是 "citrus",现在我处理的词是 "A"+"kaa" ,它的等效值是 "A "+"柑橘" = "柑橘"

在我的 textbox.text 中,我的第五个输入字符是 "m",现在我处理的单词是 "kaam"。 =81=],字典里没有。现在我们拆分字符“m”并在 dict 中检查它,是否找到它,如果找到,那么我们替换它的 equvilent 值。现在我处理的词是 "A"+'kaa'+"m" 它的值是 "A"+"citurs"+"is",我的textbox.text如下"柑橘"

第六个输入的单词是“a”,现在我处理的字符是“A”+“kaa”+“ma”等值是“A” +“柑橘”+“更多”。 Textbox.text 变成 "Acitrusmore"

现在,如果我按 "i""m" set 中找不到的字符。所以我们分开 "i" sepreately 并在 dict 中检查它,如果找到,替换该值或保持原样。

如果第 7 个输入字符是 " space bar" 那么进程将结束。

如果我的第 8 个输入字符是一些英文字母,一旦开始处理并替换 equvilaent 值等等

更新 : 2 更多清关:

在我看来,你只需要这个:

import re

[...]

TAMIL_DICT = {
    'a':'அ', 'aa':'ஆ',
    'k':'க்', 'ka':'க', 'kaa':'கா', 'ki':'கி', 'kii':'கீ', 'ku':'கு', 'kuu':'கூ',
    'm':'ம்', 'ma':'ம', 'maa':'மா', 'mi':'மி', 'mii':'மீ', 'mu':'மு', 'muu':'மூ',
    'i':'இ',
    'e':'ஈ',  # [...]
}
TAMIL_KEYS = [re.escape(key) for key in sorted(TAMIL_DICT, key=len, reverse=True)]
TAMIL_REGEX = re.compile('|'.join(TAMIL_KEYS))

def convert_to_tamil(s):
    return TAMIL_REGEX.sub(lambda match: TAMIL_DICT[match.group(0)], s)

[...]

    def func_textbox_textchanged(self, txt):
        self.tbox2.setText(convert_to_tamil(txt))

测试:

def test_convert_to_tamil():
    test_vectors = [
        ('', ''),
        ('k', 'க்'),
        ('ku', 'கு'),
        ('kuu', 'கூ'),
        ('kuum', 'கூம்'),
        ('VAkuum!', 'VAகூம்!'),
        ('!?', '!?'),
        ('ami', 'அமி'),
        ('aami', 'ஆமி'),
        ('kaaa.', 'காஅ.'),
        ('xka-aau', 'xக-ஆu')
    ]
    for v in test_vectors:
        c = convert_to_tamil(v[0])
        if c != v[1]:
            return f"'{v[0]}': expected '{v[1]}', found '{c}'"
    return "OK"

print(test_convert_to_tamil())

测试输出:

OK

它是如何工作的:正则表达式扫描输入字符串并替换它。由于它搜索的内容是按长度递减排序的(key=len, reverse=True),它总是会替换最长的匹配项,然后从它后面​​的第一个字符继续扫描。

要确认按长度递减排序很重要,请尝试将 reverse=True 替换为 reverse=False。如果你这样做,并且 运行 test_convert_to_tamil(),你将得到这个输出:

'ku': expected 'கு', found 'க்u'

请注意 TAMIL_DICT 的格式与您的 tamil_dict 格式不同。


更新

以上是基于您想要使用两个字段的理解,就像您在代码中所做的那样。可以为一个字段修改上面的代码,但代价是处理光标位置会导致大量头疼,这也必须与 QT 的光标位置逻辑很好地配合。无论如何,这是一个尝试:

TAMIL_DICT = {
    'a':'அ', 'aa':'ஆ',
    'k':'க்', 'ka':'க', 'kaa':'கா', 'ki':'கி', 'kii':'கீ', 'ku':'கு', 'kuu':'கூ',
    'm':'ம்', 'ma':'ம', 'maa':'மா', 'mi':'மி', 'mii':'மீ', 'mu':'மு', 'muu':'மூ',
    'i':'இ',
    'e':'ஈ',  # [...]
}
LATIN_DICT = {val: key for key, val in TAMIL_DICT.items()}

TAMIL_DICT_WITH_CURSOR = {}
for latin, tamil in TAMIL_DICT.items():
    for i in range(1, len(latin)):
        TAMIL_DICT_WITH_CURSOR[f"{latin[:i]}\a{latin[i:]}"] = f"{tamil}\a"
TAMIL_DICT.update(TAMIL_DICT_WITH_CURSOR)

LATIN_DICT_WITH_CURSOR = {}
for tamil, latin in LATIN_DICT.items():
    for i in range(1, len(tamil)):
        LATIN_DICT_WITH_CURSOR[f"{tamil[:i]}\a{tamil[i:]}"] = f"{latin}\a"
LATIN_DICT.update(LATIN_DICT_WITH_CURSOR)

TAMIL_KEYS = [re.escape(key) for key in sorted(TAMIL_DICT, key=len, reverse=True)]
LATIN_KEYS = [re.escape(key) for key in sorted(LATIN_DICT, key=len, reverse=True)]
TAMIL_REGEX = re.compile('|'.join(TAMIL_KEYS))
LATIN_REGEX = re.compile('|'.join(LATIN_KEYS))

def convert_to_tamil(s):
    return TAMIL_REGEX.sub(lambda match: TAMIL_DICT[match.group(0)], s)

def convert_to_latin(s):
    return LATIN_REGEX.sub(lambda match: LATIN_DICT[match.group(0)], s)


class Keyboard_Dict(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Tamil Input")
        self.tbox1 = QLineEdit()
        self.tbox1.setFont(QFont('Arial Unicode MS', 10, QFont.Bold))
        self.tbox1.textEdited.connect(self.func_textbox_textedited)
        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.tbox1)
        self.setLayout(self.vbox)

    def func_textbox_textedited(self, mixed):
        at = self.tbox1.cursorPosition()
        mixed_a = f"{mixed[:at]}\a{mixed[at:]}"
        latin_a = convert_to_latin(mixed_a)
        tamil_a = convert_to_tamil(latin_a)
        tamil = tamil_a.replace('\a', '')
        if tamil != mixed:
            self.tbox1.setText(tamil)
            self.tbox1.setCursorPosition(tamil_a.find('\a'))

请注意使用 textEdited 而不是 textChanged。这是因为 textChanged 会在 setText().

上调用

工作原理:在每次编辑时,文本都会被转换为拉丁字符,然后(尽可能)再次转换回泰米尔文字。光标位置在文本中暂时标记为“报警”或“铃”字符,\a,以便在双重转换后能够定位光标。每次转换都会将 \a 留在原处,或者,如果它位于已识别组的中间,则将其移动到已转换组的末尾。也可以移动到其他位置,但其他选择似乎问题更大,特别是因为QT允许用户删除修饰符,但不能将光标移动到被修饰字符和修饰符之间的位置。

必须注意以“来回”工作的方式构建映射。请记住,在每个编辑步骤(也可能是将字符串粘贴到文本框中!),在最常见的情况下,由所有泰米尔字符和一个拉丁字符组成的文本将被转换为所有拉丁字符的中间表示形式,然后回到泰米尔语字符。转换拉丁语→泰米尔语→拉丁语 可能 ,具有某些映射,而不是 return 到初始表示,并且这 可能 导致问题(但不一定,因为中间的完整拉丁表示对用户不可见)。请参阅评论以获取示例。


附录

查看 this table,@Bala 指出(N.B。:不要按原样使用它!),似乎需要同时输入 ASCII 和泰米尔数字。有一个简单的解决方案:

TAMIL_DICT = {
    [...]
    '`0': '௦',
    '`1': '௧',
    '`2': '௨',
    [...]
    '`9': '௯',
    '`10': '௰',
    '`100': '௱',
    '`1000': '௲',
    [...]

链接 table 中包含反引号或数字的所有 其他条目应 添加到 TAMIL_DICT .效果将是:不以 ` 开头的 ASCII 数字将保持未转换,以 ` 开头的 ASCII 数字将转换为泰米尔数字(return 转换为 `–ASCII中间拉丁表示中的数字序列),` 后面没有 ASCII 数字将保持未转换状态。唯一的缺点是不可能有 `–ASCII 数字序列作为最终结果(即,在泰米尔语表示中)。

可以通过修改两个正则表达式和使用它们的代码来改进对数字的处理,以便将 单个 反引号后跟 ASCII 数字转换为泰米尔语序列数字,反之亦然(不要忘记 10、100、1000 和其他可能的特殊情况)。要生成 ௧௨௩௪௫,您需要键入 `12345 而不是 `1`2`3`4`5