Skip to content

Commit 2466123

Browse files
committedJul 8, 2015
Improve command suggestions (new algorithm)
Signed-off-by: Chris Warrick <kwpolska@gmail.com>
1 parent c3952b1 commit 2466123

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed
 

‎nikola/__main__.py

+34-9
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,15 @@ def run(self, cmd_args):
317317
if args[0] not in sub_cmds.keys():
318318
LOGGER.error("Unknown command {0}".format(args[0]))
319319
sugg = defaultdict(list)
320-
for c in sub_cmds.keys():
321-
d = lev(c, args[0])
320+
sub_filtered = (i for i in sub_cmds.keys() if i != 'run')
321+
for c in sub_filtered:
322+
d = levenshtein(c, args[0])
322323
sugg[d].append(c)
323-
LOGGER.info('Did you mean "{}"?', '" or "'.join(sugg[min(sugg.keys())]))
324+
best_sugg = sugg[min(sugg.keys())]
325+
if len(best_sugg) == 1:
326+
LOGGER.info('Did you mean "{}"?'.format(best_sugg[0]))
327+
else:
328+
LOGGER.info('Did you mean "{}" or "{}"?'.format('", "'.join(best_sugg[:-1]), best_sugg[-1]))
324329
return 3
325330
if sub_cmds[args[0]] is not Help and not isinstance(sub_cmds[args[0]], Command): # Is a doit command
326331
if not self.nikola.configured:
@@ -334,12 +339,32 @@ def print_version():
334339
print("Nikola v" + __version__)
335340

336341

337-
# Stolen from http://stackoverflow.com/questions/4173579/implementing-levenshtein-distance-in-python
338-
def lev(a, b):
339-
if not a or not b:
340-
return max(len(a), len(b))
341-
return min(lev(a[1:], b[1:]) + (a[0] != b[0]), lev(a[1:], b) + 1, lev(a, b[1:]) + 1)
342-
342+
def levenshtein(s1, s2):
343+
"""Calculate the Levenshtein distance of two strings.
344+
345+
Implementation from Wikibooks:
346+
https://en.wikibooks.org/w/index.php?title=Algorithm_Implementation/Strings/Levenshtein_distance&oldid=2974448#Python
347+
Copyright © The Wikibooks contributors (CC BY-SA/fair use citation); edited to match coding style and add an exception.
348+
"""
349+
if len(s1) < len(s2):
350+
return levenshtein(s2, s1)
351+
352+
# len(s1) >= len(s2)
353+
if len(s2) == 0:
354+
return len(s1)
355+
356+
previous_row = range(len(s2) + 1)
357+
for i, c1 in enumerate(s1):
358+
current_row = [i + 1]
359+
for j, c2 in enumerate(s2):
360+
# j+1 instead of j since previous_row and current_row are one character longer than s2
361+
insertions = previous_row[j + 1] + 1
362+
deletions = current_row[j] + 1
363+
substitutions = previous_row[j] + (c1 != c2)
364+
current_row.append(min(insertions, deletions, substitutions))
365+
previous_row = current_row
366+
367+
return previous_row[-1]
343368

344369
if __name__ == "__main__":
345370
sys.exit(main(sys.argv[1:]))

0 commit comments

Comments
 (0)
Please sign in to comment.