diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 4baf212be7290..a718a1461d91e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -3353,8 +3353,8 @@ public static int SplitAny(this ReadOnlySpan source, Span destinati string.CheckStringSplitOptions(options); // If the separators list is empty, whitespace is used as separators. In that case, we want to ignore TrimEntries if specified, - // since TrimEntries also impacts whitespace. - if (separators.IsEmpty) + // since TrimEntries also impacts whitespace. The TrimEntries flag must be left intact if we are constrained by count because we need to process last substring. + if (separators.IsEmpty && destination.Length > source.Length) { options &= ~StringSplitOptions.TrimEntries; } @@ -3394,8 +3394,8 @@ public static int SplitAny(this ReadOnlySpan source, Span destinati string.CheckStringSplitOptions(options); // If the separators list is empty, whitespace is used as separators. In that case, we want to ignore TrimEntries if specified, - // since TrimEntries also impacts whitespace. - if (separators.IsEmpty) + // since TrimEntries also impacts whitespace. The TrimEntries flag must be left intact if we are constrained by count because we need to process last substring. + if (separators.IsEmpty && destination.Length > source.Length) { options &= ~StringSplitOptions.TrimEntries; } 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 0255aceb4183c..7c3236a8dd23a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -1508,9 +1508,10 @@ private string[] SplitInternal(ReadOnlySpan separators, int count, StringS return CreateSplitArrayOfThisAsSoleValue(options, count); } - if (separators.IsEmpty) + if (separators.IsEmpty && count > Length) { - // Caller is already splitting on whitespace; no need for separate trim step + // Caller is already splitting on whitespace; no need for separate trim step if the count is sufficient + // to examine the whole input. options &= ~StringSplitOptions.TrimEntries; } diff --git a/src/libraries/System.Runtime/tests/System/String.SplitTests.cs b/src/libraries/System.Runtime/tests/System/String.SplitTests.cs index ce7450c72c2db..b12bd2cb74fc4 100644 --- a/src/libraries/System.Runtime/tests/System/String.SplitTests.cs +++ b/src/libraries/System.Runtime/tests/System/String.SplitTests.cs @@ -491,6 +491,8 @@ public static void SplitNoMatchSingleResult() [InlineData(" ", ',', M, StringSplitOptions.TrimEntries, new[] { "" })] [InlineData(" ", ',', M, StringSplitOptions.RemoveEmptyEntries, new[] { " " })] [InlineData(" ", ',', M, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData("a b ", ' ', 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData(" a b ", ' ', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] public static void SplitCharSeparator(string value, char separator, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separator, count, options)); @@ -550,6 +552,12 @@ public static void SplitCharSeparator(string value, char separator, int count, S [InlineData(" ", ",", M, StringSplitOptions.TrimEntries, new[] { "" })] [InlineData(" ", ",", M, StringSplitOptions.RemoveEmptyEntries, new[] { " " })] [InlineData(" ", ",", M, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData("a b ", null, 2, StringSplitOptions.TrimEntries, new[] { "a b" })] + [InlineData("a b ", "", 2, StringSplitOptions.TrimEntries, new[] { "a b" })] + [InlineData("a b ", " ", 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData(" a b ", null, 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a b" })] + [InlineData(" a b ", "", 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a b" })] + [InlineData(" a b ", " ", 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] public static void SplitStringSeparator(string value, string separator, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separator, count, options)); @@ -610,6 +618,12 @@ public static void SplitNullCharArraySeparator_BindsToCharArrayOverload() [InlineData(" ", new[] { ',', ':' }, M, StringSplitOptions.TrimEntries, new[] { "" })] [InlineData(" ", new[] { ',', ':' }, M, StringSplitOptions.RemoveEmptyEntries, new[] { " " })] [InlineData(" ", new[] { ',', ':' }, M, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData("a b ", null, 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData("a b ", new char[0], 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData("a b ", new char[] { ' ' }, 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData(" a b ", null, 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] + [InlineData(" a b ", new char[0], 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] + [InlineData(" a b ", new char[] { ' ' }, 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] public static void SplitCharArraySeparator(string value, char[] separators, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separators, count, options)); @@ -654,6 +668,12 @@ public static void SplitCharArraySeparator(string value, char[] separators, int [InlineData(" ", new[] { ",", ":" }, M, StringSplitOptions.TrimEntries, new[] { "" })] [InlineData(" ", new[] { ",", ":" }, M, StringSplitOptions.RemoveEmptyEntries, new[] { " " })] [InlineData(" ", new[] { ",", ":" }, M, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new string[0])] + [InlineData("a b ", null, 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData("a b ", new string[0], 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData("a b ", new string[] { " " }, 2, StringSplitOptions.TrimEntries, new[] { "a", "b" })] + [InlineData(" a b ", null, 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] + [InlineData(" a b ", new string[0], 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] + [InlineData(" a b ", new string[] { " " }, 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries, new[] { "a", "b" })] public static void SplitStringArraySeparator(string value, string[] separators, int count, StringSplitOptions options, string[] expected) { Assert.Equal(expected, value.Split(separators, count, options));