Bash - 显示建议

时间:2014-10-30 21:28:09

标签: bash

使用Git,当我输入这样的内容时:

$ git statsu

我明白了......

git: 'statsu' is not a git command. See 'git --help'.

Did you mean this?
    status

如何使用Bash复制此内容?


当然,我可以通过制作一个巨大的case所有可能的转置字母来做到这一点......但这需要永远,而且看起来真的很脏......

case $1 in
  "statsu")
    suggestion="status"
  ;;
  "satsus")
    suggestion="status"
  ;;
  ...
esac

如何在我自己的程序中复制此行为?

(相关问题here,但这是关于配置git ITSELF来打印此消息)

1 个答案:

答案 0 :(得分:5)

(我不知道这是git完全是这样做的,但它会起作用)。有一个名为edit distance的概念可用于衡量两个字符串彼此之间的距离。在这种情况下,您可以计算输入(statsu)与每个可能匹配(statuscommitrebase等)之间的编辑距离,然后建议那个产生最小编辑距离的那个。

Wagner-Fischer算法虽然效率低下,但可以很容易地递归实现,但它应该足够快,以便为您的用例进行比较的短字符串。

# Warning: not tested, but should be close
# return (cost) is in variable wf_cost
wagner_fischer () {
    local t0 t1 t2
    if [[ -z $1 ]]; then
        # Base case 1: first string is empty
        wf_cost=${#2}
    elif [[ -z $2 ]]; then
        # Base case 2: second string is empty
        wf_cost=${#1}
    elif [[ ${1:0:1} == ${2:0:1} ]]; then
        # Strings have identical first characters, recurse on the
        # rest of each string
        wagner_fischer "${1:1}" "${2:1}"
    else
        # Strings have differing first characters; recurse on
        # the rest of each string, but add 1 to the result to accommodate
        # the initial difference.
        #
        # Pick lowest cost of possible operations:
        wagner_fischer "${1:1}" "$2"     # deletion case
        t0=$wf_cost
        wagner_fischer "${1}" "${2:1}"   # insertion case
        t1=$wf_cost
        (( t0 < t1 )) && t1=$t0
        wagner_fischer "${1:1}" "${2:1}" # substitution case
        t2=$wf_cost
        (( t1 < t2 )) && t1=$t2
        (( wf_cost=t1 + 1))
    fi
}

要找到最接近的建议,您可以使用上述功能:

min_cost=65535  # "Infinity"
for choice in status rebase commit; do
    wagner_fischer "$input" "$choice"
    if (( wf_cost < min_cost )); then
        min_cost=$wf_cost
        suggestion=$choice
    fi
done
echo "You typed $input, did you mean $suggestion?"