rokojori_action_library/Runtime/Text/Levenshtein.cs

102 lines
2.2 KiB
C#

using Godot;
using Rokojori.Extensions;
namespace Rokojori;
public class LevenshteinFuzzyMatch
{
public int lowestDistance;
public int index;
}
public class LevenshteinDistance
{
protected static int[,] GetMatrix( int aLength, int bLength )
{
var matrix = new int[ aLength + 1, bLength + 1];
for ( var i = 0; i <= aLength; i++ )
{
matrix[ i, 0 ] = i;
}
for ( var j = 0; j <= bLength; j++ )
{
matrix[ 0, j ] = j;
}
return matrix;
}
public static LevenshteinFuzzyMatch ComputeFuzzyMatch( string value, string matcher )
{
var result = new LevenshteinFuzzyMatch();
if ( matcher.Length >= value.Length )
{
result.index = 0;
result.lowestDistance = LevenshteinDistance.Compute( value, matcher );
}
else
{
var offsets = value.Length - matcher.Length;
for ( var i = 0; i < offsets; i++ )
{
var subValue = value.Substring( i, matcher.Length );
var 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;
}
public static int Compute( string a, string b )
{
var aLength = a.Length;
var bLength = b.Length;
if ( aLength == 0 ) { return bLength; }
if ( bLength == 0 ) { return aLength; }
var evaluationMatrix = LevenshteinDistance.GetMatrix( aLength, bLength );
for ( var i = 1; i <= aLength; i++ )
{
for ( var j = 1; j <= bLength; j++ )
{
var isSame = b[ j - 1 ] == a[ i - 1 ];
var isDifferentCost = isSame ? 0 : 1;
var insertionCost = evaluationMatrix[ i - 1, j ] + 1;
var deletionCost = evaluationMatrix[ i , j - 1 ] + 1;
var substitutionCost = evaluationMatrix[ i - 1, j - 1 ] + isDifferentCost;
evaluationMatrix[ i , j ] = Mathf.Min( Mathf.Min( insertionCost, deletionCost ), substitutionCost );
}
}
return evaluationMatrix[ aLength, bLength ];
}
}