From 14116abbb8f58b4884d4ca464d420ad7e7c88cfb Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Fri, 9 Oct 2026 00:22:55 +0200 Subject: [PATCH] Identify if a string is a number: .NET 10, empty-string guard, stricter double check - Retarget all three projects from net7.0 to net10.0. - Bump Microsoft.NET.Test.Sdk 18.10.1, xunit 2.9.3, xunit.runner.visualstudio 4.0.0, coverlet.collector 10.1.0, BenchmarkDotNet 0.15.8. - UsingCharIsDigit, UsingCharIsDigitWithForeach and UsingCharIsBetween09 now return false for an empty string (All() over an empty sequence is true and an empty foreach never runs). Add an empty-string row to all seven theories (42 tests to 49). - DoubleTryParse uses NumberStyles.Float | NumberStyles.AllowThousands instead of NumberStyles.Any, so "(5)" is no longer accepted; InvariantCulture stays. - Program.cs: fix the "Char.IdDigit" label and demonstrate all seven approaches. - Benchmark: add a second input, "a12345678", that fails on its first character. --- .../BenchmarkRunner/BenchmarkRunner.csproj | 4 ++-- .../StringIsANumberBenchmark.cs | 17 ++++++++-------- .../IdentifyIfAStringIsANumber.Tests.csproj | 10 +++++----- .../StringIsNumberTests.cs | 7 +++++++ .../IdentifyIfAStringIsANumber.csproj | 2 +- .../IdentifyIfAStringIsANumber/Program.cs | 20 ++++++++++++++++++- .../StringIsANumberChecker.cs | 11 ++++++++-- 7 files changed, 52 insertions(+), 19 deletions(-) diff --git a/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/BenchmarkRunner.csproj b/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/BenchmarkRunner.csproj index d41f87f394..f691b718f6 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/BenchmarkRunner.csproj +++ b/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/BenchmarkRunner.csproj @@ -2,13 +2,13 @@ Exe - net7.0 + net10.0 enable enable - + diff --git a/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/StringIsANumberBenchmark.cs b/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/StringIsANumberBenchmark.cs index 3e242ab600..c6426d125e 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/StringIsANumberBenchmark.cs +++ b/strings-csharp/IdentifyIfStringIsANumber/BenchmarkRunner/StringIsANumberBenchmark.cs @@ -8,47 +8,48 @@ namespace BenchmarkRunner; [MemoryDiagnoser] public class StringIsANumberBenchmark { - private string value = "123456789"; + [Params("123456789", "a12345678")] + public string Value { get; set; } = string.Empty; [Benchmark] public void IntTryParse() { - StringIsANumberChecker.IntTryParse(value); + StringIsANumberChecker.IntTryParse(Value); } [Benchmark] public void DoubleTryParse() { - StringIsANumberChecker.DoubleTryParse(value); + StringIsANumberChecker.DoubleTryParse(Value); } [Benchmark] public void UsingRegex() { - StringIsANumberChecker.UsingRegex(value); + StringIsANumberChecker.UsingRegex(Value); } [Benchmark] public void UsingCompiledRegex() { - StringIsANumberChecker.UsingCompiledRegex(value); + StringIsANumberChecker.UsingCompiledRegex(Value); } [Benchmark] public void UsingCharIsDigit() { - StringIsANumberChecker.UsingCharIsDigit(value); + StringIsANumberChecker.UsingCharIsDigit(Value); } [Benchmark] public void UsingCharIsDigitWithForeach() { - StringIsANumberChecker.UsingCharIsDigitWithForeach(value); + StringIsANumberChecker.UsingCharIsDigitWithForeach(Value); } [Benchmark] public void UsingCharIsBetween09() { - StringIsANumberChecker.UsingCharIsBetween09(value); + StringIsANumberChecker.UsingCharIsBetween09(Value); } } diff --git a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/IdentifyIfAStringIsANumber.Tests.csproj b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/IdentifyIfAStringIsANumber.Tests.csproj index 4eaa4bb8c9..e5f5cda2df 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/IdentifyIfAStringIsANumber.Tests.csproj +++ b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/IdentifyIfAStringIsANumber.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net10.0 enable enable @@ -10,13 +10,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/StringIsNumberTests.cs b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/StringIsNumberTests.cs index 17685b4159..a032bafb60 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/StringIsNumberTests.cs +++ b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber.Tests/StringIsNumberTests.cs @@ -9,6 +9,7 @@ public class StringIsNumberTests [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingIntTryParseMethod_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.IntTryParse(value); @@ -23,6 +24,7 @@ public void GivenAString_WhenUsingIntTryParseMethod_ThenTryToParseIt(string valu [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingCharIsDigit_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.UsingCharIsDigit(value); @@ -37,6 +39,7 @@ public void GivenAString_WhenUsingCharIsDigit_ThenTryToParseIt(string value, boo [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingDoubleTryParse_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.DoubleTryParse(value); @@ -51,6 +54,7 @@ public void GivenAString_WhenUsingDoubleTryParse_ThenTryToParseIt(string value, [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingRegex_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.UsingRegex(value); @@ -65,6 +69,7 @@ public void GivenAString_WhenUsingRegex_ThenTryToParseIt(string value, bool expe [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingCompiledRegex_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.UsingCompiledRegex(value); @@ -79,6 +84,7 @@ public void GivenAString_WhenUsingCompiledRegex_ThenTryToParseIt(string value, b [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingCharIsDigitWithForeach_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.UsingCharIsDigitWithForeach(value); @@ -93,6 +99,7 @@ public void GivenAString_WhenUsingCharIsDigitWithForeach_ThenTryToParseIt(string [InlineData("abc", false)] [InlineData("414aa", false)] [InlineData("١٢٣", false)] + [InlineData("", false)] public void GivenAString_WhenUsingCharIsBetween09_ThenTryToParseIt(string value, bool expectedResult) { var result = StringIsANumberChecker.UsingCharIsBetween09(value); diff --git a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/IdentifyIfAStringIsANumber.csproj b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/IdentifyIfAStringIsANumber.csproj index f02677bf64..dfb40caafc 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/IdentifyIfAStringIsANumber.csproj +++ b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/IdentifyIfAStringIsANumber.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable diff --git a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/Program.cs b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/Program.cs index af3143724a..dc1ab0c7ed 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/Program.cs +++ b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/Program.cs @@ -25,8 +25,26 @@ Console.WriteLine($" * {item,-15} ====> {StringIsANumberChecker.UsingRegex(item)}"); } -Console.WriteLine("Using Char.IdDigit:"); +Console.WriteLine("Using char.IsAsciiDigit():"); foreach (var item in values) { Console.WriteLine($" * {item,-15} ====> {StringIsANumberChecker.UsingCharIsDigit(item)}"); } + +Console.WriteLine("Using compiled Regex:"); +foreach (var item in values) +{ + Console.WriteLine($" * {item,-15} ====> {StringIsANumberChecker.UsingCompiledRegex(item)}"); +} + +Console.WriteLine("Using char.IsAsciiDigit() with foreach:"); +foreach (var item in values) +{ + Console.WriteLine($" * {item,-15} ====> {StringIsANumberChecker.UsingCharIsDigitWithForeach(item)}"); +} + +Console.WriteLine("Using character value comparison:"); +foreach (var item in values) +{ + Console.WriteLine($" * {item,-15} ====> {StringIsANumberChecker.UsingCharIsBetween09(item)}"); +} diff --git a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/StringIsANumberChecker.cs b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/StringIsANumberChecker.cs index 0a146a7ab4..ada676b4ab 100644 --- a/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/StringIsANumberChecker.cs +++ b/strings-csharp/IdentifyIfStringIsANumber/IdentifyIfAStringIsANumber/StringIsANumberChecker.cs @@ -12,7 +12,8 @@ public static bool IntTryParse(string stringValue) public static bool DoubleTryParse(string stringValue) { - return double.TryParse(stringValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _); + return double.TryParse(stringValue, NumberStyles.Float | NumberStyles.AllowThousands, + CultureInfo.InvariantCulture, out _); } public static bool UsingRegex(string stringValue) @@ -33,11 +34,14 @@ public static bool UsingCompiledRegex(string stringValue) public static bool UsingCharIsDigit(string stringValue) { - return stringValue.All(char.IsAsciiDigit); + return !string.IsNullOrEmpty(stringValue) && stringValue.All(char.IsAsciiDigit); } public static bool UsingCharIsDigitWithForeach(string stringValue) { + if (string.IsNullOrEmpty(stringValue)) + return false; + foreach (var c in stringValue) { if (!char.IsAsciiDigit(c)) @@ -48,6 +52,9 @@ public static bool UsingCharIsDigitWithForeach(string stringValue) public static bool UsingCharIsBetween09(string stringValue) { + if (string.IsNullOrEmpty(stringValue)) + return false; + foreach (var c in stringValue) { if (c is < '0' or > '9')