library-ts/browser/text/Levehshtein.ts

109 lines
2.3 KiB
TypeScript
Raw Normal View History

2025-03-08 08:16:54 +00:00
export class LevenshteinFuzzyMatch
{
lowestDistance:number;
index:number;
}
export class LevenshteinDistance
{
protected static getMatrix( aLength:number, bLength:number )
{
let matrix:number[][] = [];
for ( let i = 0; i < aLength + 1; i++ )
{
let bArray = [];
for ( let j = 0; j < bLength + 1; j++ )
{
bArray.push( 0 );
}
matrix.push( bArray );
}
for ( let i = 0; i <= aLength; i++ )
{
matrix[ i ][ 0 ] = i;
}
for ( let j = 0; j <= bLength; j++ )
{
matrix[ 0 ][ j ] = j;
}
return matrix;
}
static computeFuzzyMatch( value:string, matcher:string )
{
let result = new LevenshteinFuzzyMatch();
if ( matcher.length >= value.length )
{
result.index = 0;
result.lowestDistance = LevenshteinDistance.compute( value, matcher );
}
else
{
let offsets = value.length - matcher.length;
for ( let i = 0; i < offsets; i++ )
{
let subValue = value.substring( i, i + matcher.length );
let distance = LevenshteinDistance.compute( subValue, matcher );
if ( i === 0 )
{
result.index = 0;
result.lowestDistance = distance;
continue;
}
if ( distance < result.lowestDistance )
{
result.index = i;
result.lowestDistance = distance;
}
}
}
return result;
}
static compute( a:string, b:string ):number
{
let aLength = a.length;
let bLength = b.length;
if ( aLength == 0 ) { return bLength; }
if ( bLength == 0 ) { return aLength; }
let evaluationMatrix = LevenshteinDistance.getMatrix( aLength, bLength );
for ( let i = 1; i <= aLength; i++ )
{
for ( let j = 1; j <= bLength; j++ )
{
let isSame = b[ j - 1 ] === a[ i - 1 ];
let isDifferentCost = isSame ? 0 : 1;
let insertionCost = evaluationMatrix[ i - 1][ j ] + 1;
let deletionCost = evaluationMatrix[ i ][ j - 1 ] + 1;
let substitutionCost = evaluationMatrix[ i - 1][ j - 1 ] + isDifferentCost;
evaluationMatrix[ i ][ j ] = Math.min( insertionCost, deletionCost, substitutionCost );
}
}
return evaluationMatrix[ aLength][ bLength ];
}
}