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);
}