diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs index 665e9b40feadf1..541045aa712aa1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs @@ -523,7 +523,14 @@ public bool EndsWith(char value, StringComparison comparisonType) /// if matches the end of this instance; otherwise, . public bool EndsWith(Rune value) { - return EndsWith(value, StringComparison.Ordinal); + if (value.IsBmp) + { + return EndsWith((char)value.Value); + } + + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)value.Value, out char highSurrogate, out char lowSurrogate); + + return Length > 1 && this[^2] == highSurrogate && this[^1] == lowSurrogate; } /// @@ -1134,7 +1141,14 @@ public bool StartsWith(char value, StringComparison comparisonType) /// if value matches the beginning of this string; otherwise, . public bool StartsWith(Rune value) { - return StartsWith(value, StringComparison.Ordinal); + if (value.IsBmp) + { + return StartsWith((char)value.Value); + } + + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)value.Value, out char highSurrogate, out char lowSurrogate); + + return Length > 1 && _firstChar == highSurrogate && this[1] == lowSurrogate; } /// 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 343cf7bc9734d8..2d4ace7d1bfdda 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -1454,9 +1454,9 @@ private string ReplaceHelper(int oldValueLength, string newValue, ReadOnlySpan public string Replace(Rune oldRune, Rune newRune) { - if (Length == 0) + if (oldRune.IsBmp && newRune.IsBmp) { - return this; + return Replace((char)oldRune.Value, (char)newRune.Value); } ReadOnlySpan oldChars = oldRune.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); @@ -1682,11 +1682,9 @@ public string[] Split(Rune separator, StringSplitOptions options = StringSplitOp /// An array whose elements contain the substrings from this instance that are delimited by . public string[] Split(Rune separator, int count, StringSplitOptions options = StringSplitOptions.None) { - ReadOnlySpan separatorSpan = separator.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); - - if (separatorSpan.Length == 1) + if (separator.IsBmp) { - return Split(separatorSpan[0], count, options); + return Split((char)separator.Value, count, options); } ArgumentOutOfRangeException.ThrowIfNegative(count); @@ -1694,7 +1692,13 @@ public string[] Split(Rune separator, int count, StringSplitOptions options = St CheckStringSplitOptions(options); // Ensure matching the string separator overload. - return (count <= 1 || Length == 0) ? CreateSplitArrayOfThisAsSoleValue(options, count) : Split(separatorSpan, count, options); + if (count <= 1 || Length == 0) + { + return CreateSplitArrayOfThisAsSoleValue(options, count); + } + + ReadOnlySpan separatorSpan = separator.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); + return Split(separatorSpan, count, options); } // Creates an array of strings by splitting this string at each @@ -2411,39 +2415,28 @@ public unsafe string Trim(char trimChar) /// public string Trim(Rune trimRune) { - if (Length == 0) + if (trimRune.IsBmp) { - return this; + return Trim((char)trimRune.Value); } - // Convert trimRune to span - ReadOnlySpan trimChars = trimRune.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)trimRune.Value, out char highSurrogate, out char lowSurrogate); // Trim start int index = 0; - while (index < Length && this.AsSpan(index).StartsWith(trimChars)) + while ((uint)(index + 1) < (uint)Length && this[index] == highSurrogate && this[index + 1] == lowSurrogate) { - index += trimChars.Length; - } - - if (index >= Length) - { - return Empty; + index += 2; } // Trim end - int endIndex = Length - 1; - while (endIndex >= index && this.AsSpan(index..(endIndex + 1)).EndsWith(trimChars)) - { - endIndex -= trimChars.Length; - } - - if (endIndex < index) + int endIndex = Length - 2; + while (endIndex > index && this[endIndex] == highSurrogate && this[endIndex + 1] == lowSurrogate) { - return Empty; + endIndex -= 2; } - return this[index..(endIndex + 1)]; + return this[index..(endIndex + 2)]; } // Removes a set of characters from the beginning and end of this string. @@ -2497,24 +2490,17 @@ public unsafe string Trim(params ReadOnlySpan trimChars) /// public string TrimStart(Rune trimRune) { - if (Length == 0) + if (trimRune.IsBmp) { - return this; + return TrimStart((char)trimRune.Value); } - // Convert trimRune to span - ReadOnlySpan trimChars = trimRune.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)trimRune.Value, out char highSurrogate, out char lowSurrogate); - // Trim start int index = 0; - while (index < Length && this.AsSpan(index).StartsWith(trimChars)) + while ((uint)(index + 1) < (uint)Length && this[index] == highSurrogate && this[index + 1] == lowSurrogate) { - index += trimChars.Length; - } - - if (index >= Length) - { - return Empty; + index += 2; } return this[index..]; @@ -2571,27 +2557,20 @@ public unsafe string TrimStart(params ReadOnlySpan trimChars) /// public string TrimEnd(Rune trimRune) { - if (Length == 0) + if (trimRune.IsBmp) { - return this; + return TrimEnd((char)trimRune.Value); } - // Convert trimRune to span - ReadOnlySpan trimChars = trimRune.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]); + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)trimRune.Value, out char highSurrogate, out char lowSurrogate); - // Trim end - int endIndex = Length - 1; - while (endIndex >= 0 && this.AsSpan(..(endIndex + 1)).EndsWith(trimChars)) + int endIndex = Length - 2; + while ((uint)endIndex < (uint)Length && this[endIndex] == highSurrogate && this[endIndex + 1] == lowSurrogate) { - endIndex -= trimChars.Length; - } - - if (endIndex < 0) - { - return Empty; + endIndex -= 2; } - return this[..(endIndex + 1)]; + return this[..(endIndex + 2)]; } // Removes a set of characters from the end of this string. diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs b/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs index f2218eb276603b..3120477f686e01 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs @@ -52,6 +52,11 @@ public bool Contains(char value, StringComparison comparisonType) /// if occurs within this string; otherwise, . public bool Contains(Rune value) { + if (value.IsBmp) + { + return Contains((char)value.Value); + } + return Contains(value, StringComparison.Ordinal); }