I've tried to make a spell checker in a wxPython GUI but I'm having trouble in cases where I have a repeating misspelling words. The function needs to set the words in red and then suggest a correction in a MessageDialog. It all works good regarding the suggestions of corrections on the MessageDialog but I can't accomplish to change the colour of a repeated misspelling word. I understand that the problem is when I get the start position of the word... it keeps on considering the first occurence of the word and ignoring the others.
for i in range(self.tx_input.GetNumberOfLines()):
line = self.tx_input.GetLineText(i)
for word in text:
if word in line and word not in suggestion:
startPos = self.tx_input.GetValue().find(word)
endPos = startPos + len(word)
self.tx_input.SetStyle(startPos, endPos, wx.TextAttr("red", "white"))
Since I'm looping over lines, I would understand if this issue happen to misspelling words is in the same line, but what is most wierd is that it also fail when the repetition is in a different line.
I need help to figure out how to keep track of word's positions that already been processed to ignore in an eventual new occurence.
class AddQuestion ( wx.Frame ):
def __init__(self,parent):
wx.Frame.__init__(self,parent,id=wx.ID_ANY, title='Grammar Checker', pos=wx.DefaultPosition, size=wx.Size(350,350), style=wx.DEFAULT_FRAME_STYLE)
self.SetBackgroundColour( wx.Colour( 0, 93, 126 ))
panel = wx.Panel(self)
mainBox = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(mainBox)
self.tx_input = wx.TextCtrl(panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(350,150), wx.TE_MULTILINE|wx.TE_RICH2)
mainBox.Add( self.tx_input, 1, wx.ALL|wx.EXPAND, 5 )
btnBox = wx.BoxSizer(wx.VERTICAL)
self.btn = wx.Button(panel, wx.ID_ANY,u'Grammar Check', wx.DefaultPosition, wx.DefaultSize,0)
btnBox.Add(self.btn,0,wx.ALL,5)
mainBox.Add(btnBox,0,wx.ALL|wx.ALIGN_CENTER,5)
self.btn.Bind(wx.EVT_BUTTON, self.grammarCheck)
def warn(self, parent, message, caption = 'WARNING!'):
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_WARNING)
dlg.ShowModal()
dlg.Destroy()
def grammarCheck(self, event):
from symspellpy import SymSpell
sym_spell = SymSpell()
sym_spell.load_dictionary("frequency_dictionary_en_82_765.txt", 0, 1)
input_term = self.tx_input.GetValue().lower()
# filter unecessary character
ignore = r'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~1234567890“”–'
text = sym_spell.word_segmentation(input_term.translate(str.maketrans("","",ignore)), max_edit_distance=2 ).segmented_string.split()
suggestion = sym_spell.word_segmentation(input_term.translate(str.maketrans("","",ignore)), max_edit_distance=2 ).corrected_string.split()
for i in range(self.tx_input.GetNumberOfLines()):
line = self.tx_input.GetLineText(i)
for word in text:
if word in line and word not in suggestion:
startPos = self.tx_input.GetValue().find(word)
endPos = startPos + len(word)
self.tx_input.SetStyle(startPos, endPos, wx.TextAttr("red", "white"))
for i in range(len(text)):
if text[i] != suggestion[i]:
self.warn(self, "`" + text[i] + "`" + " did you mean " + "`" + suggestion[i] + "` ?")
if __name__ == '__main__':
app = wx.App(False)
frame = AddQuestion(None)
frame.Show()
app.MainLoop()
You are always looking for the first occurrence using string.find(word)
Look up something like "python find all occurrences of sub-string", I found:
# using list comprehension + startswith()
# All occurrences of substring in string
res = [i for i in range(len(test_str)) if test_str.startswith(test_sub, i)]
and
import re
# using re.finditer()
# All occurrences of substring in string
res = [i.start() for i in re.finditer(test_sub, test_str)]
both return a list of start positions within the test string and can be adapted to your code