From 0f40f7bf58bebd89d50622bbb9b4ab05c0a23deb Mon Sep 17 00:00:00 2001 From: Reister Hansjoerg Date: Mon, 22 Sep 2025 14:14:00 +0200 Subject: [PATCH] Refactor Quoters/Delimiters and add validation logic Refactored `Quoters` and `Delimiters` properties to use private backing fields and added validation to prevent overlapping characters between them. Introduced a constant error message `CommonCharactersErrorMessage` for validation failures. Changed `CsvDelimiters` to use `ImmutableHashSet` for immutability. Added a new test case `TestMethodSingleCommon` to ensure validation logic works as expected. Updated imports to include `System.Collections.Immutable`. --- SplitQuotedString/QuotedStringSplitter.cs | 37 ++++++++++++++++++++--- TestProject1/Test1.cs | 5 +++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/SplitQuotedString/QuotedStringSplitter.cs b/SplitQuotedString/QuotedStringSplitter.cs index 5875257..f38eb9c 100644 --- a/SplitQuotedString/QuotedStringSplitter.cs +++ b/SplitQuotedString/QuotedStringSplitter.cs @@ -1,4 +1,5 @@ -using System.Text; +using System.Collections.Immutable; +using System.Text; namespace HunnyR.Tools; @@ -25,6 +26,8 @@ public class QuotedStringSplitter /// public bool TreatTwoQuotesAsLiteral { get; set; } = false; + private const string CommonCharactersErrorMessage = "The delimiters and quoters have common characters. This might lead to undesired result. Quoters will always be evaluated first!"; + /// /// quote characters /// default are double quote(") and single quote (') @@ -33,16 +36,42 @@ public class QuotedStringSplitter /// '"a.b"' will return ["a.b"] not matter what delimiters /// ''a.b'' will return ["a","b"] if . is the delimiter and TreatTwoQuotesAsLiteral as literal is false else it will return ["'a.b'"] /// - public HashSet Quoters { get; set; } = ['"', '\'']; + private HashSet _quoters= ['"', '\'']; + public HashSet Quoters { + get {return this._quoters; } + set { + if (value.Intersect(this.Delimiters).Any()) + { + throw new ArgumentException(CommonCharactersErrorMessage, nameof(this.Quoters)); + } + + this._quoters = [..value]; // create a copy! + } + } /// /// delimiters /// default is space and tab /// should contain at least one character. if empty will return the full string as single token /// - public HashSet Delimiters { get; set; } = [' ', '\t']; + private HashSet _delimters= [' ', '\t']; + public HashSet Delimiters { get { return this._delimters; } + set { + if (value.Intersect(this.Quoters).Any()) + { + throw new ArgumentException(CommonCharactersErrorMessage, nameof(this.Delimiters)); + } + + this._delimters = [.. value]; // create a copy! + + } + } - public static readonly HashSet CsvDelimiters = [',', ';', '\t']; + + /// + /// the delimiters typically used for CSV files + /// + public static readonly ImmutableHashSet CsvDelimiters = [',', ';', '\t']; public static IEnumerable Split( string source, HashSet delimiters, HashSet? quoters = null, bool treatConsecutiveDelimitersAsOne = false, bool treatTwoQuotesAsLiteral = false diff --git a/TestProject1/Test1.cs b/TestProject1/Test1.cs index 455e8a4..05d627e 100644 --- a/TestProject1/Test1.cs +++ b/TestProject1/Test1.cs @@ -22,6 +22,11 @@ public void TestMethodSingleDelimiter() Assert.IsTrue(result[1].Length == 0); } + [TestMethod] + public void TestMethodSingleCommon() + { + Assert.Throws(()=>new QuotedStringSplitter() { Delimiters = ['A','B'], Quoters=['A'] }); + } [TestMethod]