diff --git a/strings-csharp/CaseInsensitiveSubstringSearch/BenchmarkRunner/BenchmarkRunner.csproj b/strings-csharp/CaseInsensitiveSubstringSearch/BenchmarkRunner/BenchmarkRunner.csproj index 083757afe1..46ec814a74 100644 --- a/strings-csharp/CaseInsensitiveSubstringSearch/BenchmarkRunner/BenchmarkRunner.csproj +++ b/strings-csharp/CaseInsensitiveSubstringSearch/BenchmarkRunner/BenchmarkRunner.csproj @@ -2,13 +2,13 @@ Exe - net7.0 + net10.0 enable enable - + diff --git a/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch.csproj b/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch.csproj index f02677bf64..dfb40caafc 100644 --- a/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch.csproj +++ b/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable diff --git a/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/SubstringSearch.cs b/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/SubstringSearch.cs index db8b1143a9..cda2b1cd08 100644 --- a/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/SubstringSearch.cs +++ b/strings-csharp/CaseInsensitiveSubstringSearch/CaseInsensitiveSubstringSearch/SubstringSearch.cs @@ -28,13 +28,20 @@ public static bool StringToUpperInvariant(string sourceString, string substringT } // Regular Expression Search + // Regex.Escape() treats the search term as literal text, so a term such as "c.de" or "z*" + // is not reinterpreted as a pattern and an unmatched bracket does not throw. + // RegexOptions.CultureInvariant keeps IgnoreCase off the current culture's casing rules. public static bool RegexIsMatch(string sourceString, string substringToSearch) { return Regex - .IsMatch(sourceString, substringToSearch, RegexOptions.IgnoreCase); + .IsMatch(sourceString, + Regex.Escape(substringToSearch), + RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); } // Linq With String Equals Method Search + // This matches whole separator-delimited words, not substrings, so it answers a different + // question from the other four methods. That difference is intentional, not a bug. public static bool LinqStringEquals(string sourceString, string substringToSearch, char separator) { return sourceString diff --git a/strings-csharp/CaseInsensitiveSubstringSearch/Tests/SubstringSearchSemanticsTest.cs b/strings-csharp/CaseInsensitiveSubstringSearch/Tests/SubstringSearchSemanticsTest.cs new file mode 100644 index 0000000000..92daa4363a --- /dev/null +++ b/strings-csharp/CaseInsensitiveSubstringSearch/Tests/SubstringSearchSemanticsTest.cs @@ -0,0 +1,60 @@ +using System.Globalization; +using CaseInsensitiveSubstringSearch; + +namespace Tests +{ + [TestClass] + public class SubstringSearchSemanticsTest + { + private const string SourceString = "Code Maze"; + + [TestMethod] + [DataRow("aze")] + [DataRow("ode")] + [DataRow("e M")] + public void GivenMidWordSubstring_WhenComparingAllFiveMethods_ThenOnlyLinqStringEqualsReturnsFalse(string subStringToSearch) + { + Assert.IsTrue(SubstringSearch.StringContains(SourceString, subStringToSearch)); + Assert.IsTrue(SubstringSearch.StringIndexOf(SourceString, subStringToSearch)); + Assert.IsTrue(SubstringSearch.StringToUpperInvariant(SourceString, subStringToSearch)); + Assert.IsTrue(SubstringSearch.RegexIsMatch(SourceString, subStringToSearch)); + + Assert.IsFalse(SubstringSearch.LinqStringEquals(SourceString, subStringToSearch, ' ')); + } + + [TestMethod] + [DataRow("c.de")] + [DataRow("z*")] + [DataRow("m|q")] + [DataRow("(")] + public void GivenSearchTermHoldingRegexMetacharacters_WhenUsingRegexIsMatchMethod_ThenItAgreesWithStringContains(string subStringToSearch) + { + var expectedResult = SubstringSearch.StringContains(SourceString, subStringToSearch); + + var result = SubstringSearch.RegexIsMatch(SourceString, subStringToSearch); + + Assert.AreEqual(expectedResult, result); + Assert.IsFalse(result); + } + + [TestMethod] + public void GivenTurkishCulture_WhenSearchingForFileInsideFILE_ThenAllFourContainmentMethodsMatch() + { + var originalCulture = CultureInfo.CurrentCulture; + + try + { + CultureInfo.CurrentCulture = new CultureInfo("tr-TR"); + + Assert.IsTrue(SubstringSearch.StringContains("FILE", "file")); + Assert.IsTrue(SubstringSearch.StringIndexOf("FILE", "file")); + Assert.IsTrue(SubstringSearch.StringToUpperInvariant("FILE", "file")); + Assert.IsTrue(SubstringSearch.RegexIsMatch("FILE", "file")); + } + finally + { + CultureInfo.CurrentCulture = originalCulture; + } + } + } +} diff --git a/strings-csharp/CaseInsensitiveSubstringSearch/Tests/Tests.csproj b/strings-csharp/CaseInsensitiveSubstringSearch/Tests/Tests.csproj index fbf6af0b48..a75aead610 100644 --- a/strings-csharp/CaseInsensitiveSubstringSearch/Tests/Tests.csproj +++ b/strings-csharp/CaseInsensitiveSubstringSearch/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net10.0 enable enable @@ -9,10 +9,10 @@ - - - - + + + +