Fix replacement of same word in one line When one line had the same mispelled word, codespell was incorrectly fixing that line, even introducing new typos. This was because the list of misspelled words is not updated according to the fixes. Instead of always updating this list and making the loop more difficult, we do as following: - Cache the words that are fixed in a certain line - Fix all cases of a misspelled in each line (this means that interactive mode will fix all cases with the same suggestions... not awesome, but simplifies a lot the code) - Use a regex with re.sub() instead of the naive string.replace() function. This eliminates dumb cases of matching partial words and modifying them. Eg.: addres->address would modify addressable to addresssable. - Skip words that were already fixed by previous iteration. Thanks to Bruce Cran <bruce@cran.org.uk> for reporting this issue.
diff --git a/codespell.py b/codespell.py index 2aac706..18560b5 100755 --- a/codespell.py +++ b/codespell.py
@@ -287,6 +287,8 @@ i += 1 continue + fixed_words = set() + for word in rx.findall(line): lword = word.lower() if lword in misspellings: @@ -301,7 +303,7 @@ # or we don't have any idea fixword = misspellings[lword].data - if options.interactive: + if options.interactive and not lword in fixed_words: fix, fixword = ask_for_word_fix(lines[i - 1], word, misspellings[lword], options.interactive) @@ -309,9 +311,13 @@ if summary and fix: summary.update(lword) + if lword in fixed_words: + continue + if options.write_changes and fix: changed = True - lines[i - 1] = lines[i - 1].replace(word, fixword, 1) + lines[i - 1] = re.sub(r'\b%s\b' % word, fixword, lines[i - 1]) + fixed_words.add(lword) continue # otherwise warning was explicitly set by interactive mode