检查字符串是 Tkinter Text Widget 中的单词还是单词的一部分
Check if a string is a word or part of a word in Tkinter Text Widget
我正在为 tkinter 文本小部件开发拼写检查器。我让它工作,以便用户可以 select 一个不正确的词并替换文本小部件中不正确词的所有实例。
但是,如果该词 出现在 另一个词中,它也会替换它。我不要这个。
例如:
假设用户有一句话:
Hello how ay you today
他们将单词“are”拼错为“ay”,他们可以右键单击它以替换所有实例或单词'ay' 和 'are'。
我的问题是,字符串“ay”出现在“today”中。这意味着当用户右键单击“ay”时,它将“today”变成“todare[=54=” ]' - 将'today'中的'ay'替换为'are'
要替换我正在使用搜索功能的单词。我想检查一下拼错的单词两边的字符是否是空格,但我不知道如何实现它。
下面是我的代码(注意——这已经大大简化了,我的实际代码有数千行。在实际程序中,按钮是上下文菜单):
from spellchecker import SpellChecker
root = Tk()
notepad = Text(root)
notepad.pack()
spell_dict = SpellChecker()
def check_spelling(event):
global spell_dict
misspelt_words_list = []
paragraph_list = notepad.get('1.0', END).strip('\n').split()
notepad.tag_config('misspelt_word_tag', foreground='red', underline=1)
for word in paragraph_list:
if (word not in spell_dict) and (word not in misspelt_words_list):
misspelt_words_list.append(word)
elif (word in misspelt_words_list) and (word in spell_dict):
misspelt_words_list.remove(word)
notepad.tag_remove('misspelt_word_tag', 1.0, END)
for misspelt_word in misspelt_words_list:
misspelt_word_offset = '+%dc' % len(misspelt_word)
pos_start = notepad.search(misspelt_word, '1.0', END)
while pos_start:
pos_end = pos_start + misspelt_word_offset
notepad.tag_add("misspelt_word_tag",pos_start,pos_end)
pos_start = notepad.search(misspelt_word,pos_end,END)
button = Button(root, text = "This is a test", command = check_spelling)
button.pack()
root.mainloop()
就像我之前说的,如果用户写 ll ll hello
,其中 'll' 是拼错的(假设程序会将其更正为 I'll) ,当用户按下按钮时,它应该替换所有写成'll'的words,但不会替换'll' 在'你好'。
这个:
ll ll hello
-> I'll I'll hello
,
不是:
ll ll hello
-> I'll I'll heI'llo
感谢您的帮助。
(我正在使用 Windows 10 和 Python 3.7)
您的问题的解决方案是使用 regular expressions。正则表达式让您搜索的不仅仅是文本。您还可以搜索模式和其他元字符。例如,表达式只能匹配行首或词首的字符串。
在你的例子中,你想要找到完整的单词。在文本小部件 search
方法的上下文中,可以通过用 \m
(单词开头)和 \M
(单词结尾)包围您正在搜索的字符串来搜索整个单词字)。
例如,要仅搜索整个单词 "ll",您应该搜索 \mll\M
。因为反斜杠在python中是一个特殊字符,我们需要将反斜杠传递给search
方法,所以需要对其进行保护。最简单的方法是使用原始字符串。
因此,给定变量中的一个词(例如:word="ll"
),我们可以制作如下所示的模式:
pattern = r'\m{}\M'.format(word)
要在搜索中使用该模式,我们需要将 search
方法的 regexp
参数设置为 True
。还有一些其他事情需要完成。我们想让 search
方法告诉我们有多少字符与模式匹配。在搜索 "ll" 的情况下,我们知道它总是两个字符,但一个好的通用解决方案是让搜索机制告诉我们。我们可以通过将 IntVar
传递给 search
方法来做到这一点。
我们需要做的另一件事是确保搜索在小部件的末尾停止,否则,它将绕回开头并永远继续搜索。
一旦我们准备好所有这些,我们就可以在文本小部件中搜索字符串 "ll",仅作为整个单词,如下所示:
countvar = IntVar()
pos = "1.0"
pattern = r'\mll\M'
pos = notepad.search(pattern, pos, "end", count=countvar, regexp=True)
pos_end = notepad.index("{} + {} chars".format(pos, countvar.get()))
因此,pos
标志着比赛的开始,pos_end
标志着比赛的结束。如果 pos
是空字符串,那么我们知道 tkinter 没有找到匹配项(在这种情况下我们可以跳过计算 pos_end
)。
总而言之,我们可以创建一个通用函数来查找并突出显示列表中的所有单词,如下所示:
def highlight_words(widget, tag, word_list):
"""Find all whole words in word_list and apply the given tag"""
widget.tag_remove(tag, "1.0", END)
countvar = IntVar()
for word in word_list:
pos = "1.0"
pattern = r"\m{}\M".format(word)
while widget.compare(pos, "<", "end"):
pos = widget.search(pattern, pos, "end", count=countvar, regexp=True)
if pos:
pos_end = widget.index("{} + {} chars".format(pos, countvar.get()))
widget.tag_add(tag,pos,pos_end)
pos = pos_end
else:
break
我们可以这样使用这个函数:
root = Tk()
notepad = Text(root)
notepad.pack()
notepad.tag_configure("misspelt_word_tag", background="pink")
notepad.insert("end", "ll ll hello")
misspelt_word_list = ['ll']
highlight_words(notepad, "misspelt_word_tag", misspelt_word_list)
root.mainloop()
有关正则表达式的概述,请参阅 documentation for the re module。
文本小部件 search
方法中使用的正则表达式与 python 正则表达式略有不同。例如,python 使用 \b
表示单词的开头或结尾,而 search
方法使用 \m
和 \M
。有关 search
方法使用的表达式语法的详细说明,请参阅 Tcl 的 re_syntax man page
我正在为 tkinter 文本小部件开发拼写检查器。我让它工作,以便用户可以 select 一个不正确的词并替换文本小部件中不正确词的所有实例。 但是,如果该词 出现在 另一个词中,它也会替换它。我不要这个。
例如:
假设用户有一句话:
Hello how ay you today
他们将单词“are”拼错为“ay”,他们可以右键单击它以替换所有实例或单词'ay' 和 'are'。
我的问题是,字符串“ay”出现在“today”中。这意味着当用户右键单击“ay”时,它将“today”变成“todare[=54=” ]' - 将'today'中的'ay'替换为'are'
要替换我正在使用搜索功能的单词。我想检查一下拼错的单词两边的字符是否是空格,但我不知道如何实现它。 下面是我的代码(注意——这已经大大简化了,我的实际代码有数千行。在实际程序中,按钮是上下文菜单):
from spellchecker import SpellChecker
root = Tk()
notepad = Text(root)
notepad.pack()
spell_dict = SpellChecker()
def check_spelling(event):
global spell_dict
misspelt_words_list = []
paragraph_list = notepad.get('1.0', END).strip('\n').split()
notepad.tag_config('misspelt_word_tag', foreground='red', underline=1)
for word in paragraph_list:
if (word not in spell_dict) and (word not in misspelt_words_list):
misspelt_words_list.append(word)
elif (word in misspelt_words_list) and (word in spell_dict):
misspelt_words_list.remove(word)
notepad.tag_remove('misspelt_word_tag', 1.0, END)
for misspelt_word in misspelt_words_list:
misspelt_word_offset = '+%dc' % len(misspelt_word)
pos_start = notepad.search(misspelt_word, '1.0', END)
while pos_start:
pos_end = pos_start + misspelt_word_offset
notepad.tag_add("misspelt_word_tag",pos_start,pos_end)
pos_start = notepad.search(misspelt_word,pos_end,END)
button = Button(root, text = "This is a test", command = check_spelling)
button.pack()
root.mainloop()
就像我之前说的,如果用户写 ll ll hello
,其中 'll' 是拼错的(假设程序会将其更正为 I'll) ,当用户按下按钮时,它应该替换所有写成'll'的words,但不会替换'll' 在'你好'。
这个:
ll ll hello
-> I'll I'll hello
,
不是:
ll ll hello
-> I'll I'll heI'llo
感谢您的帮助。
(我正在使用 Windows 10 和 Python 3.7)
您的问题的解决方案是使用 regular expressions。正则表达式让您搜索的不仅仅是文本。您还可以搜索模式和其他元字符。例如,表达式只能匹配行首或词首的字符串。
在你的例子中,你想要找到完整的单词。在文本小部件 search
方法的上下文中,可以通过用 \m
(单词开头)和 \M
(单词结尾)包围您正在搜索的字符串来搜索整个单词字)。
例如,要仅搜索整个单词 "ll",您应该搜索 \mll\M
。因为反斜杠在python中是一个特殊字符,我们需要将反斜杠传递给search
方法,所以需要对其进行保护。最简单的方法是使用原始字符串。
因此,给定变量中的一个词(例如:word="ll"
),我们可以制作如下所示的模式:
pattern = r'\m{}\M'.format(word)
要在搜索中使用该模式,我们需要将 search
方法的 regexp
参数设置为 True
。还有一些其他事情需要完成。我们想让 search
方法告诉我们有多少字符与模式匹配。在搜索 "ll" 的情况下,我们知道它总是两个字符,但一个好的通用解决方案是让搜索机制告诉我们。我们可以通过将 IntVar
传递给 search
方法来做到这一点。
我们需要做的另一件事是确保搜索在小部件的末尾停止,否则,它将绕回开头并永远继续搜索。
一旦我们准备好所有这些,我们就可以在文本小部件中搜索字符串 "ll",仅作为整个单词,如下所示:
countvar = IntVar()
pos = "1.0"
pattern = r'\mll\M'
pos = notepad.search(pattern, pos, "end", count=countvar, regexp=True)
pos_end = notepad.index("{} + {} chars".format(pos, countvar.get()))
因此,pos
标志着比赛的开始,pos_end
标志着比赛的结束。如果 pos
是空字符串,那么我们知道 tkinter 没有找到匹配项(在这种情况下我们可以跳过计算 pos_end
)。
总而言之,我们可以创建一个通用函数来查找并突出显示列表中的所有单词,如下所示:
def highlight_words(widget, tag, word_list):
"""Find all whole words in word_list and apply the given tag"""
widget.tag_remove(tag, "1.0", END)
countvar = IntVar()
for word in word_list:
pos = "1.0"
pattern = r"\m{}\M".format(word)
while widget.compare(pos, "<", "end"):
pos = widget.search(pattern, pos, "end", count=countvar, regexp=True)
if pos:
pos_end = widget.index("{} + {} chars".format(pos, countvar.get()))
widget.tag_add(tag,pos,pos_end)
pos = pos_end
else:
break
我们可以这样使用这个函数:
root = Tk()
notepad = Text(root)
notepad.pack()
notepad.tag_configure("misspelt_word_tag", background="pink")
notepad.insert("end", "ll ll hello")
misspelt_word_list = ['ll']
highlight_words(notepad, "misspelt_word_tag", misspelt_word_list)
root.mainloop()
有关正则表达式的概述,请参阅 documentation for the re module。
文本小部件 search
方法中使用的正则表达式与 python 正则表达式略有不同。例如,python 使用 \b
表示单词的开头或结尾,而 search
方法使用 \m
和 \M
。有关 search
方法使用的表达式语法的详细说明,请参阅 Tcl 的 re_syntax man page