@@ -570,51 +570,45 @@ internal static bool IsLWS(char ch)
570
570
return ( ch <= ' ' ) && ( ch == ' ' || ch == '\n ' || ch == '\r ' || ch == '\t ' ) ;
571
571
}
572
572
573
- //
574
573
// Is this a Bidirectional control char.. These get stripped
575
- //
576
- internal static bool IsBidiControlCharacter ( char ch )
577
- {
578
- return ( ch == '\u200E ' /*LRM*/ || ch == '\u200F ' /*RLM*/ || ch == '\u202A ' /*LRE*/ ||
579
- ch == '\u202B ' /*RLE*/ || ch == '\u202C ' /*PDF*/ || ch == '\u202D ' /*LRO*/ ||
580
- ch == '\u202E ' /*RLO*/ ) ;
581
- }
574
+ internal static bool IsBidiControlCharacter ( char ch ) =>
575
+ char . IsBetween ( ch , '\u200E ' , '\u202E ' ) && ! char . IsBetween ( ch , '\u2010 ' , '\u2029 ' ) ;
582
576
583
- //
584
577
// Strip Bidirectional control characters from this string
585
- //
586
578
internal static unsafe string StripBidiControlCharacters( ReadOnlySpan < char > strToClean , string ? backingString = null )
587
579
{
588
580
Debug . Assert ( backingString is null || strToClean . Length == backingString . Length ) ;
589
581
590
582
int charsToRemove = 0 ;
591
- foreach ( char c in strToClean )
583
+
584
+ int indexOfPossibleCharToRemove = strToClean . IndexOfAnyInRange ( '\u200E ' , '\u202E ' ) ;
585
+ if ( indexOfPossibleCharToRemove >= 0 )
592
586
{
593
- if ( ( uint ) ( c - '\u200E ' ) <= ( '\u202E ' - '\u200E ' ) && IsBidiControlCharacter ( c ) )
587
+ // Slow path: Contains chars that fall in the [u200E, u202E] range (so likely Bidi)
588
+ foreach ( char c in strToClean . Slice ( indexOfPossibleCharToRemove ) )
594
589
{
595
- charsToRemove++ ;
590
+ if ( IsBidiControlCharacter ( c ) )
591
+ {
592
+ charsToRemove ++ ;
593
+ }
596
594
}
597
595
}
598
596
599
597
if ( charsToRemove == 0 )
600
598
{
599
+ // Hot path
601
600
return backingString ?? new string ( strToClean ) ;
602
601
}
603
602
604
- if ( charsToRemove == strToClean . Length )
605
- {
606
- return string . Empty ;
607
- }
608
-
609
603
fixed ( char * pStrToClean = & MemoryMarshal . GetReference ( strToClean ) )
610
604
{
611
- return string . Create( strToClean . Length - charsToRemove , ( StrToClean : ( IntPtr ) pStrToClean, strToClean . Length ) , ( buffer , state ) =>
605
+ return string . Create( strToClean . Length - charsToRemove , ( StrToClean : ( IntPtr ) pStrToClean, strToClean . Length ) , static ( buffer , state ) =>
612
606
{
613
607
var strToClean = new ReadOnlySpan < char > ( ( char * ) state . StrToClean , state . Length ) ;
614
608
int destIndex = 0 ;
615
609
foreach ( char c in strToClean )
616
610
{
617
- if ( ( uint ) ( c - ' \u200E ' ) > ( ' \u202E ' - ' \u200E ' ) || ! IsBidiControlCharacter ( c ) )
611
+ if ( ! IsBidiControlCharacter ( c ) )
618
612
{
619
613
buffer [ destIndex ++ ] = c ;
620
614
}
0 commit comments