일치 점수를 제공하는 퍼지 문자열 일치 프로그램이 있습니까?


17

file A과 file 에 문자열 목록이 있습니다 B. 파일 A에서 각 문자열을 가져 와서 파일 B에서 가장 유사한 문자열을 찾고 싶습니다.

이를 위해 퍼지 비교를 제공하는 도구를 찾고 있습니다.

예를 들면 다음과 같습니다.

$ fuzzy_compare "Some string" "Some string"
100

여기서 100은 일부 동등 비율입니다. 예를 들어 Levenshtein distance 입니다.

유틸리티가 있습니까? 바퀴를 재발 명하고 싶지 않습니다.


1
명확성을 높이기 위해 귀하의 질문을 편집했지만 첫 번째 문자열뿐만 아니라 fileA의 문자열을 fileB의 문자열 과 비교하도록 요청하도록 변경했습니다 . 나는 그것이 당신이 의미하는 것이라고 생각했지만 내가 틀렸다면 나를 정정하십시오.
terdon


@muru 아니오, 퍼지 매칭에만 해당되며 OP에는 점수가 필요합니다.
terdon

답변:


23

Levenshtein 거리 알고리즘의 구현을 다른 언어로 제공하는 이 페이지 를 찾았습니다 . 예를 들어 bash에서 다음을 수행 할 수 있습니다.

#!/bin/bash
function levenshtein {
    if [ "$#" -ne "2" ]; then
        echo "Usage: $0 word1 word2" >&2
    elif [ "${#1}" -lt "${#2}" ]; then
        levenshtein "$2" "$1"
    else
        local str1len=$((${#1}))
        local str2len=$((${#2}))
        local d i j
        for i in $(seq 0 $(((str1len+1)*(str2len+1)))); do
            d[i]=0
        done
        for i in $(seq 0 $((str1len))); do
            d[$((i+0*str1len))]=$i
        done
        for j in $(seq 0 $((str2len))); do
            d[$((0+j*(str1len+1)))]=$j
        done

        for j in $(seq 1 $((str2len))); do
            for i in $(seq 1 $((str1len))); do
                [ "${1:i-1:1}" = "${2:j-1:1}" ] && local cost=0 || local cost=1
                local del=$((d[(i-1)+str1len*j]+1))
                local ins=$((d[i+str1len*(j-1)]+1))
                local alt=$((d[(i-1)+str1len*(j-1)]+cost))
                d[i+str1len*j]=$(echo -e "$del\n$ins\n$alt" | sort -n | head -1)
            done
        done
        echo ${d[str1len+str1len*(str2len)]}
    fi
}

while read str1; do
        while read str2; do
                lev=$(levenshtein "$str1" "$str2");
                printf '%s / %s : %s\n' "$str1" "$str2" "$lev"
        done < "$2"
done < "$1"

로 저장 ~/bin/levenshtein.sh하고 실행 파일 ( chmod a+x ~/bin/levenshtein.sh)로 만들고 두 파일에서 실행하십시오. 예를 들면 다음과 같습니다.

$ cat fileA
foo
zoo
bar
fob
baar
$ cat fileB
foo
loo
baar
bob
gaf
$ a.sh fileA fileB
foo / foo : 0
foo / loo : 1
foo / baar : 4
foo / bob : 2
foo / gaf : 3
zoo / foo : 1
zoo / loo : 1
zoo / baar : 4
zoo / bob : 2
zoo / gaf : 3
bar / foo : 3
bar / loo : 3
bar / baar : 1
bar / bob : 2
bar / gaf : 2
fob / foo : 1
fob / loo : 2
fob / baar : 4
fob / bob : 1
fob / gaf : 3
baar / foo : 4
baar / loo : 4
baar / baar : 0
baar / bob : 3
baar / gaf : 3

몇 가지 패턴에는 문제가 없지만 더 큰 파일의 경우 속도 가 매우 느려집니다. 이것이 문제라면 다른 언어로 된 구현 중 하나를 시도하십시오. 예를 들어 Perl :

#!/usr/bin/perl 
use List::Util qw(min);

sub levenshtein
{
    my ($str1, $str2) = @_;
    my @ar1 = split //, $str1;
    my @ar2 = split //, $str2;

    my @dist;
    $dist[$_][0] = $_ foreach (0 .. @ar1);
    $dist[0][$_] = $_ foreach (0 .. @ar2);

    foreach my $i (1 .. @ar1) {
        foreach my $j (1 .. @ar2) {
            my $cost = $ar1[$i - 1] eq $ar2[$j - 1] ? 0 : 1;
            $dist[$i][$j] = min(
                            $dist[$i - 1][$j] + 1, 
                            $dist[$i][$j - 1] + 1, 
                            $dist[$i - 1][$j - 1] + $cost
                             );
        }
    }

    return $dist[@ar1][@ar2];
}
open(my $fh1, "$ARGV[0]");
open(my $fh2, "$ARGV[1]");
chomp(my @strings1=<$fh1>);
chomp(my @strings2=<$fh2>);

foreach my $str1 (@strings1) {
    foreach my $str2 (@strings2) {
        my $lev=levenshtein($str1, $str2);
        print "$str1 / $str2 : $lev\n";
    }
}

위와 같이 스크립트를 다른 이름으로 저장하고 ~/bin/levenshtein.pl실행 가능하게 만들고 두 파일을 인수로 사용하여 실행하십시오.

~/bin/levenstein.pl fileA fileB

여기에 사용 된 아주 작은 파일에서도 Perl 방식은 bash 방식보다 10 배 빠릅니다.

$ time levenshtein.sh fileA fileB > /dev/null

real    0m0.965s
user    0m0.070s
sys     0m0.057s

$ time levenshtein.pl fileA fileB > /dev/null
real    0m0.011s
user    0m0.010s
sys     0m0.000s

결과에 대한 더 많은 설명을 추가하려면 : 위키피디아를 인용 하면 , 두 단어 사이의 레 벤슈 테인 거리는 한 단어를 다른 단어로 변경하는 데 필요한 최소 단일 문자 편집 (즉, 삽입, 삭제 또는 대체) 수 입니다. 즉, 숫자가 낮을수록 일치하는 것이 좋습니다. 숫자 0은 완벽하게 일치 함을 의미합니다. 또한 Levenshtein 거리는 각 문자 편집을 동일하게 처리합니다. "foo"및 "Foo"는 "foo"및 "fox"와 같은 거리를 의미합니다.
scai
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.