diff --git a/FuzzySearch.Test/FuzzyTests.cs b/FuzzySearch.Test/FuzzyTests.cs
index ae0296b..97f6511 100644
--- a/FuzzySearch.Test/FuzzyTests.cs
+++ b/FuzzySearch.Test/FuzzyTests.cs
@@ -218,6 +218,22 @@ public void Contains_WithScore_CamelCaseMatch_GetsBonus()
Assert.IsGreaterThanOrEqualTo(Fuzzy.camelCaseMatchBonus, score, "Score should include camelCase bonus");
}
+ [TestMethod]
+ public void Contains_WithScore_LatePrefixMatch_ScoresLowerThanStartMatch()
+ {
+ // Arrange
+ string pattern = "foo";
+
+ // Act
+ bool earlyResult = Fuzzy.Contains("foo", pattern, out int earlyScore);
+ bool lateResult = Fuzzy.Contains("xxxxxxxxxxfoo", pattern, out int lateScore);
+
+ // Assert
+ Assert.IsTrue(earlyResult, "Start-position match should return true.");
+ Assert.IsTrue(lateResult, "Late-position match should return true.");
+ Assert.IsGreaterThan(lateScore, earlyScore, "Match at the start should score higher than a late prefix match.");
+ }
+
#endregion
#region Apply Bonuses Tests
@@ -329,7 +345,23 @@ public void PenalizeNonPatternCharacters_FirstPatternChar_AppliesPrefixPenalty()
int initialScore = 10;
int patternIdx = 0;
int strIdx = 3; // 3 chars before first match
- int expectedPenalty = Math.Max(strIdx * Fuzzy.unmatchedPrefixLetterPenalty, Fuzzy.maxPrefixPenalty);
+ int expectedPenalty = -3;
+
+ // Act
+ int result = Fuzzy.PenalizeNonPatternCharacters(initialScore, patternIdx, strIdx);
+
+ // Assert
+ Assert.AreEqual(initialScore + expectedPenalty, result);
+ }
+
+ [TestMethod]
+ public void PenalizeNonPatternCharacters_FirstPatternChar_CapsPrefixPenalty()
+ {
+ // Arrange
+ int initialScore = 10;
+ int patternIdx = 0;
+ int strIdx = 10;
+ int expectedPenalty = -5;
// Act
int result = Fuzzy.PenalizeNonPatternCharacters(initialScore, patternIdx, strIdx);
diff --git a/FuzzySearch/Fuzzy.cs b/FuzzySearch/Fuzzy.cs
index 7408e4c..6cfd9ea 100644
--- a/FuzzySearch/Fuzzy.cs
+++ b/FuzzySearch/Fuzzy.cs
@@ -27,10 +27,10 @@ public static class Fuzzy
internal const int camelCaseMatchBonus = 10;
/// The penalty for each unmatched character at the beginning of the string.
- internal const int unmatchedPrefixLetterPenalty = 0;
+ internal const int unmatchedPrefixLetterPenalty = -1;
/// The maximum prefix penalty that can be applied.
- internal const int maxPrefixPenalty = 0;
+ internal const int maxPrefixPenalty = -5;
/// The penalty for each unmatched character in the string.
internal const int unmatchedLetterPenalty = -1;
@@ -119,8 +119,6 @@ internal static int CalculateScore(ReadOnlySpan subject, ReadOnlySpan matchedIndices = [];
-
// Loop over characters in subject
while (strIdx != strLength)
{
@@ -139,7 +137,6 @@ internal static int CalculateScore(ReadOnlySpan subject, ReadOnlySpan subject, ReadOnlySpan