Расстояние Левенштейна является полезной метрикой, дающей представление о количестве различий между двумя строками. Он измеряет количество вставок, удалений и замен, необходимых для перехода от одной строки к другой.
Например, если вы сравните abcdef
и bcdef
, все символы различны, если вы сравните их один к одному, но только одно удаление нужно, чтобы перейти от одного к другому.
Таким образом, вы можете сделать свой процент как :расстояние / макс. _длина:
perl -MList::Util=max -MText::LevenshteinXS -le '
($x, $y) = @ARGV
print 100 * distance($x, $y) / max(length $x, length $x)
' -- "$string1" "$string2"
Или вawk
:
awk '
function min(x, y) {
return x < y ? x : y
}
function max(x, y) {
return x > y ? x : y
}
function lev(s,t) {
m = length(s)
n = length(t)
for(i=0;i<=m;i++) d[i,0] = i
for(j=0;j<=n;j++) d[0,j] = j
for(i=1;i<=m;i++) {
for(j=1;j<=n;j++) {
c = substr(s,i,1) != substr(t,j,1)
d[i,j] = min(d[i-1,j]+1,min(d[i,j-1]+1,d[i-1,j-1]+c))
}
}
return d[m,n]
}
BEGIN {
print 100 * lev(ARGV[1], ARGV[2]) / max(length(ARGV[1]), length(ARGV[2]))
exit
}' "$string1" "$string2"
Это дало бы 100 для a
против b
или bc
, но 50 для ab
против ac
или a
или b
или abcd
. Остерегайтесь, вы получите ошибку деления -на -ноль, если попытаетесь сравнить пустую строку с самой собой.
Они ограничены максимальной длиной аргумента команды (128 КБ в современных системах Linux ), хотя это можно обойти, получив строки другим способом (, например, прочитав их из файла ). ] если нужно.
Другой метрикой, которую вы, возможно, захотите рассмотреть, является модуль Дамерау -расстояния Левенштейна(Text::Levenshtein::Damerau
вperl
). Это то же самое, что и расстояние Левенштейна, за исключением того, что перестановка смежных символов (как в ab
противba
)считается как 1 вместо 2.
Это расстояние используется, например, при zsh
приблизительном сопоставлении (как в [[ abcd = (#a2)acbe ]]
для проверки того, что abcd
совпадает с acbe
в пределах максимального расстояния 2 )и является общим, когда оно приходит к рассмотрению человеческих опечаток или мутаций ДНК.
Следующая функция добавляет $PWD/
к любому относительному пути, прежде чем передать его в _files
, что является обычной функцией завершения для файлов.
_absolute_files () {
local expansion=$PREFIX$SUFFIX; expansion=${(e)expansion}
if [[ "${expansion%%/#}" != "${expansion:a}" ]]; then
PREFIX="\$PWD/$PREFIX"
fi
_files "$@";
}
Это работает во многих распространенных случаях, включая распознавание путей, начинающихся с ~/
и таких как абсолютные, а также путей, выраженных с помощью переменной. Я не думал обо всех возможных взаимодействиях с расширением (, например. подстановочных знаков )и с встраиванием.