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 ]; } }