diff --git a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs index 264d03d1f728bc..917908ec2a451f 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs @@ -3688,12 +3688,12 @@ internal IndexField[] ParseSortString(string sortString) IndexField[] indexDesc = Array.Empty(); if ((null != sortString) && (0 < sortString.Length)) { - string[] split = sortString.Split(','); + string[] split = sortString.Split(',', StringSplitOptions.TrimEntries); indexDesc = new IndexField[split.Length]; for (int i = 0; i < split.Length; i++) { - string current = split[i].Trim(); + string current = split[i]; // handle ASC and DESC. int length = current.Length; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs index f110c70d31d3ee..1147dee06a7948 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs @@ -107,25 +107,7 @@ private HttpEnvironmentProxy(Uri? httpProxy, Uri? httpsProxy, string? bypassList _httpsProxyUri = httpsProxy; _credentials = HttpEnvironmentProxyCredentials.TryCreate(httpProxy, httpsProxy); - - if (!string.IsNullOrWhiteSpace(bypassList)) - { - string[] list = bypassList.Split(','); - List tmpList = new List(list.Length); - - foreach (string value in list) - { - string tmp = value.Trim(); - if (tmp.Length > 0) - { - tmpList.Add(tmp); - } - } - if (tmpList.Count > 0) - { - _bypass = tmpList.ToArray(); - } - } + _bypass = bypassList?.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); } /// diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpWebSocket.cs b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpWebSocket.cs index c53818676fba44..d474242626e016 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpWebSocket.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpWebSocket.cs @@ -62,14 +62,14 @@ internal static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketPro // here, we know that the client has specified something, it's not empty // and the server has specified exactly one protocol - string[] requestProtocols = clientSecWebSocketProtocol.Split(',', StringSplitOptions.RemoveEmptyEntries); + string[] requestProtocols = clientSecWebSocketProtocol.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); acceptProtocol = subProtocol; // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that // this exists in the list the client specified. for (int i = 0; i < requestProtocols.Length; i++) { - string currentRequestProtocol = requestProtocols[i].Trim(); + string currentRequestProtocol = requestProtocols[i]; if (string.Equals(acceptProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase)) { return true; diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 2fe2781e2b71b8..00ff97b8455e51 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -1270,19 +1270,30 @@ private string[] SplitInternal(ReadOnlySpan separators, int count, StringS throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount); - if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) - throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, options)); + CheckStringSplitOptions(options); - bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries); - - if ((count == 0) || (omitEmptyEntries && Length == 0)) + ShortCircuit: + if (count <= 1 || Length == 0) { - return Array.Empty(); + // Per the method's documentation, we'll short-circuit the search for separators. + // But we still need to post-process the results based on the caller-provided flags. + + string candidate = this; + if (((options & StringSplitOptions.TrimEntries) != 0) && (count > 0)) + { + candidate = candidate.Trim(); + } + if (((options & StringSplitOptions.RemoveEmptyEntries) != 0) && (candidate.Length == 0)) + { + count = 0; + } + return (count == 0) ? Array.Empty() : new string[] { candidate }; } - if (count == 1) + if (separators.IsEmpty) { - return new string[] { this }; + // Caller is already splitting on whitespace; no need for separate trim step + options &= ~StringSplitOptions.TrimEntries; } var sepListBuilder = new ValueListBuilder(stackalloc int[StackallocIntBufferSizeLimit]); @@ -1293,12 +1304,13 @@ private string[] SplitInternal(ReadOnlySpan separators, int count, StringS // Handle the special case of no replaces. if (sepList.Length == 0) { - return new string[] { this }; + count = 1; + goto ShortCircuit; } - string[] result = omitEmptyEntries - ? SplitOmitEmptyEntries(sepList, default, 1, count) - : SplitKeepEmptyEntries(sepList, default, 1, count); + string[] result = (options != StringSplitOptions.None) + ? SplitWithPostProcessing(sepList, default, 1, count, options) + : SplitWithoutPostProcessing(sepList, default, 1, count); sepListBuilder.Dispose(); @@ -1333,33 +1345,45 @@ private string[] SplitInternal(string? separator, string?[]? separators, int cou SR.ArgumentOutOfRange_NegativeCount); } - if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) - { - throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)options)); - } - - bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries); + CheckStringSplitOptions(options); bool singleSeparator = separator != null; if (!singleSeparator && (separators == null || separators.Length == 0)) { + // split on whitespace return SplitInternal(default(ReadOnlySpan), count, options); } - if ((count == 0) || (omitEmptyEntries && Length == 0)) + ShortCircuit: + if (count <= 1 || Length == 0) { - return Array.Empty(); - } + // Per the method's documentation, we'll short-circuit the search for separators. + // But we still need to post-process the results based on the caller-provided flags. - if (count == 1 || (singleSeparator && separator!.Length == 0)) - { - return new string[] { this }; + string candidate = this; + if (((options & StringSplitOptions.TrimEntries) != 0) && (count > 0)) + { + candidate = candidate.Trim(); + } + if (((options & StringSplitOptions.RemoveEmptyEntries) != 0) && (candidate.Length == 0)) + { + count = 0; + } + return (count == 0) ? Array.Empty() : new string[] { candidate }; } if (singleSeparator) { - return SplitInternal(separator!, count, options); + if (separator!.Length == 0) + { + count = 1; + goto ShortCircuit; + } + else + { + return SplitInternal(separator, count, options); + } } var sepListBuilder = new ValueListBuilder(stackalloc int[StackallocIntBufferSizeLimit]); @@ -1375,9 +1399,9 @@ private string[] SplitInternal(string? separator, string?[]? separators, int cou return new string[] { this }; } - string[] result = omitEmptyEntries - ? SplitOmitEmptyEntries(sepList, lengthList, 0, count) - : SplitKeepEmptyEntries(sepList, lengthList, 0, count); + string[] result = (options != StringSplitOptions.None) + ? SplitWithPostProcessing(sepList, lengthList, 0, count, options) + : SplitWithoutPostProcessing(sepList, lengthList, 0, count); sepListBuilder.Dispose(); lengthListBuilder.Dispose(); @@ -1394,19 +1418,27 @@ private string[] SplitInternal(string separator, int count, StringSplitOptions o if (sepList.Length == 0) { // there are no separators so sepListBuilder did not rent an array from pool and there is no need to dispose it - return new string[] { this }; + string candidate = this; + if ((options & StringSplitOptions.TrimEntries) != 0) + { + candidate = candidate.Trim(); + } + return ((candidate.Length == 0) && ((options & StringSplitOptions.RemoveEmptyEntries) != 0)) + ? Array.Empty() + : new string[] { candidate }; } - string[] result = options == StringSplitOptions.RemoveEmptyEntries - ? SplitOmitEmptyEntries(sepList, default, separator.Length, count) - : SplitKeepEmptyEntries(sepList, default, separator.Length, count); + string[] result = (options != StringSplitOptions.None) + ? SplitWithPostProcessing(sepList, default, separator.Length, count, options) + : SplitWithoutPostProcessing(sepList, default, separator.Length, count); sepListBuilder.Dispose(); return result; } - private string[] SplitKeepEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count) + // This function will not trim entries or special-case empty entries + private string[] SplitWithoutPostProcessing(ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count) { Debug.Assert(count >= 2); @@ -1442,8 +1474,8 @@ private string[] SplitKeepEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count) + // This function may trim entries or omit empty entries + private string[] SplitWithPostProcessing(ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count, StringSplitOptions options) { Debug.Assert(count >= 2); @@ -1458,19 +1490,40 @@ private string[] SplitOmitEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan thisEntry; + + for (int i = 0; i < numReplaces; i++) { - if (sepList[i] - currIndex > 0) + thisEntry = this.AsSpan(currIndex, sepList[i] - currIndex); + if ((options & StringSplitOptions.TrimEntries) != 0) { - splitStrings[arrIndex++] = Substring(currIndex, sepList[i] - currIndex); + thisEntry = thisEntry.Trim(); + } + if (!thisEntry.IsEmpty || ((options & StringSplitOptions.RemoveEmptyEntries) == 0)) + { + splitStrings[arrIndex++] = thisEntry.ToString(); } currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]); if (arrIndex == count - 1) { - // If all the remaining entries at the end are empty, skip them - while (i < numReplaces - 1 && currIndex == sepList[++i]) + // The next iteration of the loop will provide the final entry into the + // results array. If needed, skip over all empty entries before that + // point. + if ((options & StringSplitOptions.RemoveEmptyEntries) != 0) { - currIndex += (lengthList.IsEmpty ? defaultLength : lengthList[i]); + while (++i < numReplaces) + { + thisEntry = this.AsSpan(currIndex, sepList[i] - currIndex); + if ((options & StringSplitOptions.TrimEntries) != 0) + { + thisEntry = thisEntry.Trim(); + } + if (!thisEntry.IsEmpty) + { + break; // there's useful data here + } + currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]); + } } break; } @@ -1479,22 +1532,20 @@ private string[] SplitOmitEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan @@ -1639,6 +1690,17 @@ private void MakeSeparatorList(string?[] separators, ref ValueListBuilder s } } + private static void CheckStringSplitOptions(StringSplitOptions options) + { + const StringSplitOptions AllValidFlags = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries; + + if ((options & ~AllValidFlags) != 0) + { + // at least one invalid flag was set + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + } + // Returns a substring of this string. // public string Substring(int startIndex) => Substring(startIndex, Length - startIndex); diff --git a/src/libraries/System.Private.CoreLib/src/System/StringSplitOptions.cs b/src/libraries/System.Private.CoreLib/src/System/StringSplitOptions.cs index d7020559a1d1ca..7ddac3edf3616e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/StringSplitOptions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/StringSplitOptions.cs @@ -4,10 +4,45 @@ namespace System { + // Examples of StringSplitOptions combinations: + // + // string str = "a,,b, c, , d ,e"; + // + // string[] split = str.Split(',', StringSplitOptions.None); + // split := [ "a", "", "b", " c", " ", " d ", "e" ] + // + // string[] split = str.Split(',', StringSplitOptions.RemoveEmptyEntries); + // split := [ "a", "b", " c", " ", " d ", "e" ] + // + // string[] split = str.Split(',', StringSplitOptions.TrimEntries); + // split := [ "a", "", "b", "c", "", "d", "e" ] + // + // string[] split = str.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + // split := [ "a", "b", "c", "d", "e" ] + + /// + /// Specifies how the results should be transformed when splitting a string into substrings. + /// [Flags] public enum StringSplitOptions { + /// + /// Do not transform the results. This is the default behavior. + /// None = 0, - RemoveEmptyEntries = 1 + + /// + /// Remove empty (zero-length) substrings from the result. + /// + /// + /// If and are specified together, + /// then substrings that consist only of whitespace characters are also removed from the result. + /// + RemoveEmptyEntries = 1, + + /// + /// Trim whitespace from each substring in the result. + /// + TrimEntries = 2 } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index f3180254cc80e8..4610536d949d78 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -3546,6 +3546,7 @@ public enum StringSplitOptions { None = 0, RemoveEmptyEntries = 1, + TrimEntries = 2, } public partial class SystemException : System.Exception { diff --git a/src/libraries/System.Runtime/tests/System/String.SplitTests.cs b/src/libraries/System.Runtime/tests/System/String.SplitTests.cs index 9ccb1a16c6df74..9b0f009166f150 100644 --- a/src/libraries/System.Runtime/tests/System/String.SplitTests.cs +++ b/src/libraries/System.Runtime/tests/System/String.SplitTests.cs @@ -30,24 +30,24 @@ public static void SplitInvalidOptions() const string value = "a,b"; const int count = int.MaxValue; const StringSplitOptions optionsTooLow = StringSplitOptions.None - 1; - const StringSplitOptions optionsTooHigh = StringSplitOptions.RemoveEmptyEntries + 1; + const StringSplitOptions optionsTooHigh = (StringSplitOptions)0x04; - AssertExtensions.Throws(null, () => value.Split(',', optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(',', optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(',', count, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(',', count, optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(new[] { ',' }, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(new[] { ',' }, optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(new[] { ',' }, count, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(new[] { ',' }, count, optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(",", optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(",", optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(",", count, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(",", count, optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(new[] { "," }, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(new[] { "," }, optionsTooHigh)); - AssertExtensions.Throws(null, () => value.Split(new[] { "," }, count, optionsTooLow)); - AssertExtensions.Throws(null, () => value.Split(new[] { "," }, count, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(',', optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(',', optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(',', count, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(',', count, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(new[] { ',' }, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(new[] { ',' }, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(new[] { ',' }, count, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(new[] { ',' }, count, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(",", optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(",", optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(",", count, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(",", count, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(new[] { "," }, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(new[] { "," }, optionsTooHigh)); + AssertExtensions.Throws("options", () => value.Split(new[] { "," }, count, optionsTooLow)); + AssertExtensions.Throws("options", () => value.Split(new[] { "," }, count, optionsTooHigh)); } [Fact] @@ -423,6 +423,30 @@ public static void SplitNoMatchSingleResult() [InlineData("first,second,third", ' ', M, StringSplitOptions.RemoveEmptyEntries, new[] { "first,second,third" })] [InlineData("Foo Bar Baz", ' ', 2, StringSplitOptions.RemoveEmptyEntries, new[] { "Foo", "Bar Baz" })] [InlineData("Foo Bar Baz", ' ', M, StringSplitOptions.None, new[] { "Foo", "Bar", "Baz" })] + [InlineData("a", ',', 0, StringSplitOptions.None, new string[0])] + [InlineData("a", ',', 0, StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData("a", ',', 0, StringSplitOptions.TrimEntries, new string[0])] + [InlineData("a", ',', 0, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[0])] + [InlineData("a", ',', 1, StringSplitOptions.None, new string[] { "a" })] + [InlineData("a", ',', 1, StringSplitOptions.RemoveEmptyEntries, new string[] { "a" })] + [InlineData("a", ',', 1, StringSplitOptions.TrimEntries, new string[] { "a" })] + [InlineData("a", ',', 1, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[] { "a" })] + [InlineData(" ", ',', 0, StringSplitOptions.None, new string[0])] + [InlineData(" ", ',', 0, StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData(" ", ',', 0, StringSplitOptions.TrimEntries, new string[0])] + [InlineData(" ", ',', 0, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[0])] + [InlineData(" ", ',', 1, StringSplitOptions.None, new string[] { " " })] + [InlineData(" ", ',', 1, StringSplitOptions.RemoveEmptyEntries, new string[] { " " })] + [InlineData(" ", ',', 1, StringSplitOptions.TrimEntries, new string[] { "" })] + [InlineData(" ", ',', 1, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[0])] + [InlineData(" a,, b, c ", ',', 2, StringSplitOptions.None, new string[] { " a", ", b, c " })] + [InlineData(" a,, b, c ", ',', 2, StringSplitOptions.RemoveEmptyEntries, new string[] { " a", " b, c " })] + [InlineData(" a,, b, c ", ',', 2, StringSplitOptions.TrimEntries, new string[] { "a", ", b, c" })] + [InlineData(" a,, b, c ", ',', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[] { "a", "b, c" })] + [InlineData(" a,, b, c ", ',', 3, StringSplitOptions.None, new string[] { " a", "", " b, c " })] + [InlineData(" a,, b, c ", ',', 3, StringSplitOptions.RemoveEmptyEntries, new string[] { " a", " b", " c " })] + [InlineData(" a,, b, c ", ',', 3, StringSplitOptions.TrimEntries, new string[] { "a", "", "b, c" })] + [InlineData(" a,, b, c ", ',', 3, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new string[] { "a", "b", "c" })] public static void SplitCharSeparator(string value, char separator, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separator, count, options)); @@ -456,6 +480,10 @@ public static void SplitCharSeparator(string value, char separator, int count, S [InlineData("aaabaaabaaa", "aa", M, StringSplitOptions.None, new[] { "", "ab", "ab", "a" })] [InlineData("aaabaaabaaa", "aa", M, StringSplitOptions.RemoveEmptyEntries, new[] { "ab", "ab", "a" })] [InlineData("this, is, a, string, with some spaces", ", ", M, StringSplitOptions.None, new[] { "this", "is", "a", "string", "with some spaces" })] + [InlineData("Monday, Tuesday, Wednesday, Thursday, Friday", ",", M, StringSplitOptions.TrimEntries, new[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" })] + [InlineData("Monday, Tuesday,\r, Wednesday,\n, Thursday, Friday", ",", M, StringSplitOptions.TrimEntries, new[] { "Monday", "Tuesday", "", "Wednesday", "", "Thursday", "Friday" })] + [InlineData("Monday, Tuesday,\r, Wednesday,\n, Thursday, Friday", ",", M, StringSplitOptions.RemoveEmptyEntries, new[] { "Monday", " Tuesday", "\r", " Wednesday", "\n", " Thursday", " Friday" })] + [InlineData("Monday, Tuesday,\r, Wednesday,\n, Thursday, Friday", ",", M, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" })] public static void SplitStringSeparator(string value, string separator, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separator, count, options)); @@ -499,6 +527,10 @@ public static void SplitNullCharArraySeparator_BindsToCharArrayOverload() [InlineData("this, is, a, string, with some spaces", new[] { ',', ' ' }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "this", "is", "a", "string", "with", "some", "spaces" })] [InlineData("this, is, a, string, with some spaces", new[] { ',', ' ', 's' }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", "i", "a", "tring", "with", "ome", "pace" })] [InlineData("this, is, a, string, with some spaces", new[] { ',', ' ', 's', 'a' }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", "i", "tring", "with", "ome", "p", "ce" })] + [InlineData("this, is, a, string, with some spaces", new[] { ',', 's', 'a' }, M, StringSplitOptions.None, new[] { "thi" /*s*/, "" /*,*/, " i" /*s*/, "" /*,*/, " " /*a*/, "" /*,*/, " " /*s*/, "tring" /*,*/, " with " /*s*/, "ome " /*s*/, "p" /*a*/, "ce" /*s*/, "" })] + [InlineData("this, is, a, string, with some spaces", new[] { ',', 's', 'a' }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", " i", " ", " ", "tring", " with ", "ome ", "p", "ce" })] + [InlineData("this, is, a, string, with some spaces", new[] { ',', 's', 'a' }, M, StringSplitOptions.TrimEntries, new[] { "thi", "", "i", "", "", "", "", "tring", "with", "ome", "p", "ce", "" })] + [InlineData("this, is, a, string, with some spaces", new[] { ',', 's', 'a' }, M, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new[] { "thi", "i", "tring", "with", "ome", "p", "ce" })] public static void SplitCharArraySeparator(string value, char[] separators, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separators, count, options)); @@ -522,6 +554,14 @@ public static void SplitCharArraySeparator(string value, char[] separators, int [InlineData("this, is, a, string, with some spaces", new[] { ", ", " " }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "this", "is", "a", "string", "with", "some", "spaces" })] [InlineData("this, is, a, string, with some spaces", new[] { ",", " ", "s" }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", "i", "a", "tring", "with", "ome", "pace" })] [InlineData("this, is, a, string, with some spaces", new[] { ",", " ", "s", "a" }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", "i", "tring", "with", "ome", "p", "ce" })] + [InlineData("this, is, a, string, with some spaces", new[] { ",", "s", "a" }, M, StringSplitOptions.None, new[] { "thi" /*s*/, "" /*,*/, " i" /*s*/, "" /*,*/, " " /*a*/, "" /*,*/, " " /*s*/, "tring" /*,*/, " with " /*s*/, "ome " /*s*/, "p" /*a*/, "ce" /*s*/, "" })] + [InlineData("this, is, a, string, with some spaces", new[] { ",", "s", "a" }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "thi", " i", " ", " ", "tring", " with ", "ome ", "p", "ce" })] + [InlineData("this, is, a, string, with some spaces", new[] { ",", "s", "a" }, M, StringSplitOptions.TrimEntries, new[] { "thi", "", "i", "", "", "", "", "tring", "with", "ome", "p", "ce", "" })] + [InlineData("this, is, a, string, with some spaces", new[] { ",", "s", "a" }, M, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new[] { "thi", "i", "tring", "with", "ome", "p", "ce" })] + [InlineData("this, is, a, string, with some spaces, ", new[] { ",", " s" }, M, StringSplitOptions.None, new[] { "this", " is", " a", "", "tring", " with", "ome", "paces", " " })] + [InlineData("this, is, a, string, with some spaces, ", new[] { ",", " s" }, M, StringSplitOptions.RemoveEmptyEntries, new[] { "this", " is", " a", "tring", " with", "ome", "paces", " " })] + [InlineData("this, is, a, string, with some spaces, ", new[] { ",", " s" }, M, StringSplitOptions.TrimEntries, new[] { "this", "is", "a", "", "tring", "with", "ome", "paces", "" })] + [InlineData("this, is, a, string, with some spaces, ", new[] { ",", " s" }, M, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, new[] { "this", "is", "a", "tring", "with", "ome", "paces" })] public static void SplitStringArraySeparator(string value, string[] separators, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separators, count, options));