Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Globalization.CompareOptions update #10087

Merged
merged 16 commits into from
Apr 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CompareOptionsExample.Run();
StringSort.Run();
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,67 +1,51 @@
// The following code example shows how sorting with CompareOptions.StringSort differs from sorting without CompareOptions.StringSort.

// <snippet1>
using System;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Globalization;

public class SamplesCompareOptions {

private class MyStringComparer: IComparer {
private CompareInfo myComp;
private CompareOptions myOptions = CompareOptions.None;

// Constructs a comparer using the specified CompareOptions.
public MyStringComparer( CompareInfo cmpi, CompareOptions options ) {
myComp = cmpi;
this.myOptions = options;
}

// Compares strings with the CompareOptions specified in the constructor.
public int Compare(Object a, Object b) {
if (a == b) return 0;
if (a == null) return -1;
if (b == null) return 1;

String sa = a as String;
String sb = b as String;
if (sa != null && sb != null)
return myComp.Compare(sa, sb, myOptions);
throw new ArgumentException("a and b should be strings.");
}
}

public static void Main() {

// Creates and initializes an array of strings to sort.
String[] myArr = new String[9] { "cant", "bill's", "coop", "cannot", "billet", "can't", "con", "bills", "co-op" };
Console.WriteLine( "\nInitially," );
foreach ( String myStr in myArr )
Console.WriteLine( myStr );

// Creates and initializes a Comparer to use.
//CultureInfo myCI = new CultureInfo( "en-US", false );
MyStringComparer myComp = new MyStringComparer(CompareInfo.GetCompareInfo("en-US"), CompareOptions.None);

// Sorts the array without StringSort.
Array.Sort( myArr, myComp );
Console.WriteLine( "\nAfter sorting without CompareOptions.StringSort:" );
foreach ( String myStr in myArr )
Console.WriteLine( myStr );

// Sorts the array with StringSort.
myComp = new MyStringComparer(CompareInfo.GetCompareInfo("en-US"), CompareOptions.StringSort);
Array.Sort( myArr, myComp );
Console.WriteLine( "\nAfter sorting with CompareOptions.StringSort:" );
foreach ( String myStr in myArr )
Console.WriteLine( myStr );
}
public class StringSort
{
public static void Run()
{
var wordList = new List<string>
{
"cant", "bill's", "coop", "cannot", "billet", "can't", "con", "bills", "co-op"
};

Console.WriteLine("Before sorting:");
foreach (string word in wordList)
{
Console.WriteLine(word);
}

Console.WriteLine(Environment.NewLine + "After sorting with CompareOptions.None:");
SortAndDisplay(wordList, CompareOptions.None);

Console.WriteLine(Environment.NewLine + "After sorting with CompareOptions.StringSort:");
SortAndDisplay(wordList, CompareOptions.StringSort);
}

// Sort the list of words with the supplied CompareOptions.
private static void SortAndDisplay(List<string> unsorted, CompareOptions options)
{
// Create a copy of the original list to sort.
var words = new List<string>(unsorted);
// Define the CompareInfo to use to compare strings.
CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;

// Sort the copy with the supplied CompareOptions then display.
words.Sort((str1, str2) => comparer.Compare(str1, str2, options));
foreach (string word in words)
{
Console.WriteLine(word);
}
}
}

/*
This code produces the following output.
CompareOptions.None and CompareOptions.StringSort provide identical ordering by default
in .NET 5 and later. But in prior versions, the output is the following:
Initially,
Before sorting:
cant
bill's
coop
@@ -72,7 +56,7 @@ This code produces the following output.
bills
co-op
After sorting without CompareOptions.StringSort:
After sorting with CompareOptions.None:
billet
bills
bill's
@@ -93,6 +77,4 @@ This code produces the following output.
co-op
con
coop
*/
// </snippet1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System;
using System.Globalization;

public class CompareOptionsExample
{
public static void Run()
{
// Uppercase and lowercase characters are equivalent (according to the culture rules)
// when IgnoreCase is used.
TestStringEquality("ONE two", "one TWO", "Case sensitivity", CompareOptions.IgnoreCase);

// Punctuation is ignored with the IgnoreSymbols option.
TestStringEquality("hello world", "hello, world!", "Punctuation", CompareOptions.IgnoreSymbols);

// Whitespace and mathematical symbols are also ignored with IgnoreSymbols.
TestStringEquality("3 + 5 = 8", "358", "Whitespace and mathematical symbols", CompareOptions.IgnoreSymbols);

// Caution: currency symbols and thousands separators are ignored with IgnoreSymbols.
// Parse strings containing numbers/currency and compare them numerically instead.
TestStringEquality("Total $15,000", "Total: £150.00", "Currency symbols, decimals and thousands separators", CompareOptions.IgnoreSymbols);

// Full width characters are common in East Asian languages. Use the IgnoreWidth
// option to treat full- and half-width characters as equal.
TestStringEquality("abc,-", "abc,-", "Half width and full width characters", CompareOptions.IgnoreWidth);

// The same string in Hiragana and Katakana is equal when IgnoreKanaType is used.
TestStringEquality("ありがとう", "アリガトウ", "Hiragana and Katakana strings", CompareOptions.IgnoreKanaType);

// When comparing with the IgnoreNonSpace option, characters like diacritical marks are ignored.
TestStringEquality("café", "cafe", "Diacritical marks", CompareOptions.IgnoreNonSpace);

// Ligature characters and their non-ligature forms compare equal with the IgnoreNonSpace option.
// Note: prior to .NET 5, ligature characters were equal to their expanded forms by default.
TestStringEquality("straße œuvre cæsar", "strasse oeuvre caesar", "Ligature characters", CompareOptions.IgnoreNonSpace);
}

private static void TestStringEquality(string str1, string str2, string description, CompareOptions options)
{
Console.WriteLine(Environment.NewLine + description + ":");
// First test with the default CompareOptions then with the provided options
TestStringEquality(str1, str2, CompareOptions.None);
TestStringEquality(str1, str2, options);
}

private static void TestStringEquality(string str1, string str2, CompareOptions options)
{
Console.Write($" When using CompareOptions.{options}, \"{str1}\" and \"{str2}\" are ");
if (string.Compare(str1, str2, CultureInfo.InvariantCulture, options) != 0)
{
Console.Write("not ");
}
Console.WriteLine("equal.");
}
}

/*
In .NET 5 and later, the output is the following:
Case sensitivity:
When using CompareOptions.None, "ONE two" and "one TWO" are not equal.
When using CompareOptions.IgnoreCase, "ONE two" and "one TWO" are equal.
Punctuation:
When using CompareOptions.None, "hello world" and "hello, world!" are not equal.
When using CompareOptions.IgnoreSymbols, "hello world" and "hello, world!" are equal.
Whitespace and mathematical symbols:
When using CompareOptions.None, "3 + 5 = 8" and "358" are not equal.
When using CompareOptions.IgnoreSymbols, "3 + 5 = 8" and "358" are equal.
Currency symbols, decimals and thousands separators:
When using CompareOptions.None, "Total $15,000" and "Total: £150.00" are not equal.
When using CompareOptions.IgnoreSymbols, "Total $15,000" and "Total: £150.00" are equal.
Half width and full width characters:
When using CompareOptions.None, "abc,-" and "abc,-" are not equal.
When using CompareOptions.IgnoreWidth, "abc,-" and "abc,-" are equal.
Hiragana and Katakana strings:
When using CompareOptions.None, "ありがとう" and "アリガトウ" are not equal.
When using CompareOptions.IgnoreKanaType, "ありがとう" and "アリガトウ" are equal.
Diacritical marks:
When using CompareOptions.None, "café" and "cafe" are not equal.
When using CompareOptions.IgnoreNonSpace, "café" and "cafe" are equal.
Ligature characters:
When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are not equal.
When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
Note: When using .NET versions prior to .NET 5, ligature characters compare as equal to their
non-ligature counterparts by default, so the last test will output as follows:
Ligature characters:
When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
*/
13 changes: 13 additions & 0 deletions snippets/fsharp/System.Globalization/Project.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="compareoptions_stringsort.fs" />
<Compile Include="compareoptions_values.fs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module compareoptions_stringsort

open System
open System.Collections.Generic
open System.Globalization

let sortAndDisplay (unsorted: List<string>) (options: CompareOptions) =
let words = new List<string>(unsorted)
let comparer = CultureInfo.InvariantCulture.CompareInfo
words.Sort((fun str1 str2 -> comparer.Compare(str1, str2, options)))
for word in words do
printfn "%s" word

[<EntryPoint>]
let main argv =
let wordList = new List<string>(
["cant"; "bill's"; "coop"; "cannot"; "billet"; "can't"; "con"; "bills"; "co-op"])

printfn "Before sorting:"
for word in wordList do
printfn "%s" word

printfn "\nAfter sorting with CompareOptions.None:"
sortAndDisplay wordList CompareOptions.None

printfn "\nAfter sorting with CompareOptions.StringSort:"
sortAndDisplay wordList CompareOptions.StringSort

0 // return an integer exit code

(*
CompareOptions.None and CompareOptions.StringSort provide identical ordering by default
in .NET 5 and later, but in prior versions, the output will be the following:
Before sorting:
cant
bill's
coop
cannot
billet
can't
con
bills
co-op
After sorting with CompareOptions.None:
billet
bills
bill's
cannot
cant
can't
con
coop
co-op
After sorting with CompareOptions.StringSort:
bill's
billet
bills
can't
cannot
cant
co-op
con
coop
*)
90 changes: 90 additions & 0 deletions snippets/fsharp/System.Globalization/compareoptions_values.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module compareoptions_values

open System
open System.Globalization

let testStringEquality (str1: string) (str2: string) (description: string) (options: CompareOptions) =
printfn "\n%s:" description

let compareAndPrint opts =
let result = String.Compare(str1, str2, CultureInfo.InvariantCulture, opts)
let equalityStatus = if result = 0 then "equal" else "not equal"
printfn " When using CompareOptions.%A, \"%s\" and \"%s\" are %s." opts str1 str2 equalityStatus

compareAndPrint CompareOptions.None
compareAndPrint options

[<EntryPoint>]
let main argv =
// Uppercase and lowercase characters are equivalent (according to the culture rules) when IgnoreCase is used.
testStringEquality "ONE two" "one TWO" "Case sensitivity" CompareOptions.IgnoreCase

// Punctuation is ignored with the IgnoreSymbols option.
testStringEquality "hello world" "hello, world!" "Punctuation" CompareOptions.IgnoreSymbols

// Whitespace and mathematical symbols are also ignored with IgnoreSymbols.
testStringEquality "3 + 5 = 8" "358" "Whitespace and mathematical symbols" CompareOptions.IgnoreSymbols

// Caution: currency symbols and thousands separators are ignored with IgnoreSymbols.
// Parse strings containing numbers/currency and compare them numerically instead.
testStringEquality "Total $15,000" "Total: £150.00" "Currency symbols, decimals and thousands separators" CompareOptions.IgnoreSymbols

// Full width characters are common in East Asian languages. Use the IgnoreWidth
// option to treat full- and half-width characters as equal.
testStringEquality "abc,-" "abc,-" "Half width and full width characters" CompareOptions.IgnoreWidth

// The same string in Hiragana and Katakana is equal when IgnoreKanaType is used.
testStringEquality "ありがとう" "アリガトウ" "Hiragana and Katakana strings" CompareOptions.IgnoreKanaType

// When comparing with the IgnoreNonSpace option, characters like diacritical marks are ignored.
testStringEquality "café" "cafe" "Diacritical marks" CompareOptions.IgnoreNonSpace

// Ligature characters and their non-ligature forms compare equal with the IgnoreNonSpace option.
// Note: prior to .NET 5, ligature characters were equal to their expanded forms by default.
testStringEquality "straße œuvre cæsar" "strasse oeuvre caesar" "Ligature characters" CompareOptions.IgnoreNonSpace

0 // return an integer exit code

(*
In .NET 5 and later, the output will be the following:
Case sensitivity:
When using CompareOptions.None, "ONE two" and "one TWO" are not equal.
When using CompareOptions.IgnoreCase, "ONE two" and "one TWO" are equal.
Punctuation:
When using CompareOptions.None, "hello world" and "hello, world!" are not equal.
When using CompareOptions.IgnoreSymbols, "hello world" and "hello, world!" are equal.
Whitespace and mathematical symbols:
When using CompareOptions.None, "3 + 5 = 8" and "358" are not equal.
When using CompareOptions.IgnoreSymbols, "3 + 5 = 8" and "358" are equal.
Currency symbols, decimals and thousands separators:
When using CompareOptions.None, "Total $15,000" and "Total: £150.00" are not equal.
When using CompareOptions.IgnoreSymbols, "Total $15,000" and "Total: £150.00" are equal.
Half width and full width characters:
When using CompareOptions.None, "abc,-" and "abc,-" are not equal.
When using CompareOptions.IgnoreWidth, "abc,-" and "abc,-" are equal.
Hiragana and Katakana strings:
When using CompareOptions.None, "ありがとう" and "アリガトウ" are not equal.
When using CompareOptions.IgnoreKanaType, "ありがとう" and "アリガトウ" are equal.
Diacritical marks:
When using CompareOptions.None, "café" and "cafe" are not equal.
When using CompareOptions.IgnoreNonSpace, "café" and "cafe" are equal.
Ligature characters:
When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are not equal.
When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
Note: when using .NET versions prior to .NET 5, ligature characters compare as equal to their
non-ligature counterparts by default, so the last test will output as follows:
Ligature characters:
When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
*)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,87 +1,46 @@
' The following code example shows how sorting with CompareOptions.StringSort differs from sorting without CompareOptions.StringSort.

' <snippet1>
Imports System.Collections
Imports System
Imports System.Collections.Generic
Imports System.Globalization

Public Class SamplesCompareOptions

Private Class MyStringComparer
Implements IComparer

Private myComp As CompareInfo
Private myOptions As CompareOptions = CompareOptions.None

' Constructs a comparer using the specified CompareOptions.
Public Sub New(cmpi As CompareInfo, options As CompareOptions)
myComp = cmpi
Me.myOptions = options
End Sub

' Compares strings with the CompareOptions specified in the constructor.
Public Function Compare(a As [Object], b As [Object]) As Integer Implements IComparer.Compare
If a = b Then
Return 0
End If
If a Is Nothing Then
Return - 1
End If
If b Is Nothing Then
Return 1
End If
Public Class StringSort
Public Shared Sub Main()
Dim wordList As New List(Of String) From {
"cant", "bill's", "coop", "cannot", "billet", "can't", "con", "bills", "co-op"
}

Dim sa As [String] = a
Dim sb As [String] = b
If Not (sa Is Nothing) And Not (sb Is Nothing) Then
Return myComp.Compare(sa, sb, myOptions)
End If
Throw New ArgumentException("a and b should be strings.")
Console.WriteLine("Before sorting:")
For Each word In wordList
Console.WriteLine(word)
Next

End Function 'Compare
Console.WriteLine(Environment.NewLine & "After sorting with CompareOptions.None:")
SortAndDisplay(wordList, CompareOptions.None)

End Class
Console.WriteLine(Environment.NewLine & "After sorting with CompareOptions.StringSort:")
SortAndDisplay(wordList, CompareOptions.StringSort)
End Sub

' Sort the list of words with the supplied CompareOptions.
Private Shared Sub SortAndDisplay(unsorted As List(Of String), options As CompareOptions)
' Create a copy of the original list to sort.
Dim words As New List(Of String)(unsorted)

Public Shared Sub Main()

' Creates and initializes an array of strings to sort.
Dim myArr() As [String] = {"cant", "bill's", "coop", "cannot", "billet", "can't", "con", "bills", "co-op"}
Console.WriteLine()
Console.WriteLine("Initially,")
Dim myStr As [String]
For Each myStr In myArr
Console.WriteLine(myStr)
Next myStr
' Define the CompareInfo to use to compare strings.
Dim comparer As CompareInfo = CultureInfo.InvariantCulture.CompareInfo

' Creates and initializes a Comparer to use.
'CultureInfo myCI = new CultureInfo( "en-US", false );
Dim myComp As New MyStringComparer(CompareInfo.GetCompareInfo("en-US"), CompareOptions.None)

' Sorts the array without StringSort.
Array.Sort(myArr, myComp)
Console.WriteLine()
Console.WriteLine("After sorting without CompareOptions.StringSort:")
For Each myStr In myArr
Console.WriteLine(myStr)
Next myStr

' Sorts the array with StringSort.
myComp = New MyStringComparer(CompareInfo.GetCompareInfo("en-US"), CompareOptions.StringSort)
Array.Sort(myArr, myComp)
Console.WriteLine()
Console.WriteLine("After sorting with CompareOptions.StringSort:")
For Each myStr In myArr
Console.WriteLine(myStr)
Next myStr

End Sub
' Sort the copy with the supplied CompareOptions then display.
words.Sort(Function(str1, str2) comparer.Compare(str1, str2, options))

For Each word In words
Console.WriteLine(word)
Next
End Sub
End Class


'This code produces the following output.
' CompareOptions.None and CompareOptions.StringSort provide identical ordering by default
' in .NET 5 And later, but in prior versions, the output is the following:
'
'Initially,
'Before sorting
'cant
'bill's
'coop
@@ -91,8 +50,8 @@ End Class
'con
'bills
'co-op
'
'After sorting without CompareOptions.StringSort:

'After sorting with CompareOptions.None
'billet
'bills
'bill's
@@ -102,8 +61,8 @@ End Class
'con
'coop
'co-op
'
'After sorting with CompareOptions.StringSort:

'After sorting with CompareOptions.StringSort
'bill's
'billet
'bills
@@ -113,5 +72,3 @@ End Class
'co-op
'con
'coop

' </snippet1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Imports System
Imports System.Globalization

Module CompareOptionsExample
Sub Main()
' Uppercase and lowercase characters are equivalent (according to the culture rules)
' when IgnoreCase is used.
TestStringEquality("ONE two", "one TWO", "Case sensitivity", CompareOptions.IgnoreCase)

' Punctuation is ignored with the IgnoreSymbols option.
TestStringEquality("hello world", "hello, world!", "Punctuation", CompareOptions.IgnoreSymbols)

' Whitespace and mathematical symbols are also ignored with IgnoreSymbols.
TestStringEquality("3 + 5 = 8", "358", "Whitespace and mathematical symbols", CompareOptions.IgnoreSymbols)

' Caution: currency symbols and thousands separators are ignored with IgnoreSymbols.
' Parse strings containing numbers/currency and compare them numerically instead.
TestStringEquality("Total $15,000", "Total: £150.00", "Currency symbols, decimals and thousands separators", CompareOptions.IgnoreSymbols)

' Full width characters are common in East Asian languages. Use the IgnoreWidth
' option to treat full- and half-width characters as equal.
TestStringEquality("abc,-", "abc,-", "Half width and full width characters", CompareOptions.IgnoreWidth)

' The same string in Hiragana and Katakana is equal when IgnoreKanaType is used.
TestStringEquality("ありがとう", "アリガトウ", "Hiragana and Katakana strings", CompareOptions.IgnoreKanaType)

' When comparing with the IgnoreNonSpace option, characters like diacritical marks are ignored.
TestStringEquality("café", "cafe", "Diacritical marks", CompareOptions.IgnoreNonSpace)

' Ligature characters and their non-ligature forms compare equal with the IgnoreNonSpace option.
' Note: prior to .NET 5, ligature characters were equal to their expanded forms by default.
TestStringEquality("straße œuvre cæsar", "strasse oeuvre caesar", "Ligature characters", CompareOptions.IgnoreNonSpace)
End Sub

Private Sub TestStringEquality(str1 As String, str2 As String, description As String, options As CompareOptions)
Console.WriteLine(Environment.NewLine & description & ":")
' First test with the default CompareOptions then with the provided options
TestStringEqualityWithOptions(str1, str2, CompareOptions.None)
TestStringEqualityWithOptions(str1, str2, options)
End Sub

Private Sub TestStringEqualityWithOptions(str1 As String, str2 As String, options As CompareOptions)
Console.Write($" When using CompareOptions.{options}, ""{str1}"" and ""{str2}"" are ")
If String.Compare(str1, str2, CultureInfo.InvariantCulture, options) <> 0 Then
Console.Write("not ")
End If
Console.WriteLine("equal.")
End Sub
End Module

' In .NET 5 and later, the output is the following:
'
'Case sensitivity :
' When using CompareOptions.None, "ONE two" and "one TWO" are not equal.
' When using CompareOptions.IgnoreCase, "ONE two" and "one TWO" are equal.
'
'Punctuation:
' When using CompareOptions.None, "hello world" and "hello, world!" are not equal.
' When using CompareOptions.IgnoreSymbols, "hello world" and "hello, world!" are equal.
'
'Whitespace And mathematical symbols:
' When using CompareOptions.None, "3 + 5 = 8" and "358" are not equal.
' When using CompareOptions.IgnoreSymbols, "3 + 5 = 8" and "358" are equal.
'
'Currency symbols, decimals And thousands separators:
' When using CompareOptions.None, "Total $15,000" and "Total: £150.00" are not equal.
' When using CompareOptions.IgnoreSymbols, "Total $15,000" and "Total: £150.00" are equal.
'
'Half width And full width characters:
' When using CompareOptions.None, "abc,-" and "abc,-" are not equal.
' When using CompareOptions.IgnoreWidth, "abc,-" and "abc,-" are equal.
'
'Hiragana And Katakana strings:
' When using CompareOptions.None, "ありがとう" and "アリガトウ" are not equal.
' When using CompareOptions.IgnoreKanaType, "ありがとう" and "アリガトウ" are equal.
'
'Diacritical marks :
' When using CompareOptions.None, "café" and "cafe" are not equal.
' When using CompareOptions.IgnoreNonSpace, "café" and "cafe" are equal.
'
'Ligature characters :
' When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are not equal.
' When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
'
' Note: when using .NET versions prior to .NET 5, ligature characters compare as equal to their
' non-ligature counterparts by default, so the last test will output as follows:
'
'Ligature characters :
' When using CompareOptions.None, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
' When using CompareOptions.IgnoreNonSpace, "straße œuvre cæsar" and "strasse oeuvre caesar" are equal.
57 changes: 42 additions & 15 deletions xml/System.Globalization/CompareOptions.xml
Original file line number Diff line number Diff line change
@@ -68,15 +68,42 @@
</Attribute>
</Attributes>
<Docs>
<summary>Defines the string comparison options to use with <see cref="T:System.Globalization.CompareInfo" />.</summary>
<remarks>For more information about this API, see <see href="/dotnet/fundamentals/runtime-libraries/system-globalization-compareoptions">Supplemental API remarks for CompareOptions</see>.</remarks>
<summary>
Defines the string comparison options to use with <see cref="T:System.Globalization.CompareInfo" />.
</summary>
<remarks>
<format type="text/markdown">
<![CDATA[
In .NET 5 and later, the cross-platform ICU (International Components for Unicode) library is used for string processing. The ICU library brings the following changes to string comparison behavior:
- The default option `None` is now equivalent to the `StringSort` option. The previous functionality of `None`, where equal weighting was given to alphanumeric and nonalphanumeric characters, is no longer available.
- Ligatures (combined characters like "æ" and "œ") are now seen as distinct from their expanded forms ("ae", "oe") in string comparisons by default. To treat ligatures and their expanded forms as equivalent, use the `IgnoreNonSpace` option.
For more information about the change, including how to restore the previous Unicode handler, see [.NET globalization and ICU](/dotnet/core/extensions/globalization-icu).
For more information about this API, see [Supplemental API remarks for CompareOptions](/dotnet/fundamentals/runtime-libraries/system-globalization-compareoptions).
]]></format>
</remarks>
<example>
The following code example shows how each of the CompareOptions values affect string comparisons.
<format type="text/markdown">
<![CDATA[
:::code language="csharp" source="~/snippets/csharp/System.Globalization/CompareOptions/Overview/compareoptions_values.cs" interactive="try-dotnet":::
:::code language="fsharp" source="~/snippets/fsharp/System.Globalization/compareoptions_values.fs":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.Globalization.CompareOptions.Values/VB/compareoptions_values.vb" id="Snippet1":::
]]>
</format>
</example>
<example>
The following code example shows how sorting with StringSort differs from sorting without StringSort.
<format type="text/markdown"><![CDATA[
:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.Globalization.CompareOptions.StringSort/CPP/compareoptions_stringsort.cpp" id="Snippet1":::
:::code language="csharp" source="~/snippets/csharp/System.Globalization/CompareOptions/Overview/compareoptions_stringsort.cs" interactive="try-dotnet" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.Globalization.CompareOptions.StringSort/VB/compareoptions_stringsort.vb" id="Snippet1":::
]]></format></example>
<format type="text/markdown">
<![CDATA[
:::code language="csharp" source="~/snippets/csharp/System.Globalization/CompareOptions/Overview/compareoptions_stringsort.cs" interactive="try-dotnet":::
:::code language="fsharp" source="~/snippets/fsharp/System.Globalization/compareoptions_stringsort.fs":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.Globalization.CompareOptions.StringSort/VB/compareoptions_stringsort.vb" id="Snippet2":::
]]>
</format>
</example>
<related type="Article" href="/dotnet/standard/base-types/basic-string-operations">Basic String Operations in .NET</related>
</Docs>
<Members>
@@ -121,7 +148,7 @@
</ReturnValue>
<MemberValue>1</MemberValue>
<Docs>
<summary>Indicates that the string comparison must ignore case.</summary>
<summary>Indicates that the string comparison ignores case differences.</summary>
</Docs>
</Member>
<Member MemberName="IgnoreKanaType">
@@ -165,7 +192,7 @@
</ReturnValue>
<MemberValue>8</MemberValue>
<Docs>
<summary>Indicates that the string comparison must ignore the Kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds in the Japanese language. Hiragana is used for native Japanese expressions and words, while katakana is used for words borrowed from other languages, such as "computer" or "Internet". A phonetic sound can be expressed in both hiragana and katakana. If this value is selected, the hiragana character for one sound is considered equal to the katakana character for the same sound.</summary>
<summary>Indicates that the string comparison ignores the kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds. Hiragana is used for native Japanese words, while katakana is used for words borrowed from other languages. With this option, hiragana and katakana characters that represent the same sound are considered equal.</summary>
</Docs>
</Member>
<Member MemberName="IgnoreNonSpace">
@@ -209,7 +236,7 @@
</ReturnValue>
<MemberValue>2</MemberValue>
<Docs>
<summary>Indicates that the string comparison must ignore nonspacing combining characters, such as diacritics. The <see href="https://go.microsoft.com/fwlink/?linkid=37123">Unicode Standard</see> defines combining characters as characters that are combined with base characters to produce a new character. Nonspacing combining characters do not occupy a spacing position by themselves when rendered.</summary>
<summary>Indicates that the string comparison ignores nonspacing combining characters, such as diacritics. Nonspacing characters modify base characters without occupying their own space. The <see href="https://home.unicode.org/">Unicode Standard</see> defines combining characters as characters that are combined with base characters to produce a new character.</summary>
</Docs>
</Member>
<Member MemberName="IgnoreSymbols">
@@ -253,7 +280,7 @@
</ReturnValue>
<MemberValue>4</MemberValue>
<Docs>
<summary>Indicates that the string comparison must ignore symbols, such as white-space characters, punctuation, currency symbols, the percent sign, mathematical symbols, the ampersand, and so on.</summary>
<summary>Indicates that the string comparison ignores symbols, including whitespace, punctuation, currency symbols, the percent sign, mathematical symbols, the ampersand, and similar characters.</summary>
</Docs>
</Member>
<Member MemberName="IgnoreWidth">
@@ -297,7 +324,7 @@
</ReturnValue>
<MemberValue>16</MemberValue>
<Docs>
<summary>Indicates that the string comparison must ignore the character width. For example, Japanese katakana characters can be written as full-width or half-width. If this value is selected, the katakana characters written as full-width are considered equal to the same characters written as half-width.</summary>
<summary>Indicates that the string comparison ignores character width. For example, full-width and half-width forms of Japanese katakana characters are considered equal with this option.</summary>
</Docs>
</Member>
<Member MemberName="None">
@@ -385,7 +412,7 @@
</ReturnValue>
<MemberValue>1073741824</MemberValue>
<Docs>
<summary>Indicates that the string comparison must use successive Unicode UTF-16 encoded values of the string (code unit by code unit comparison), leading to a fast comparison but one that is culture-insensitive. A string starting with a code unit XXXX16 comes before a string starting with YYYY16, if XXXX16 is less than YYYY16. This value cannot be combined with other <see cref="T:System.Globalization.CompareOptions" /> values and must be used alone.</summary>
<summary>Indicates that the string comparison uses the Unicode UTF-16 encoded values of the strings, comparing them code unit by code unit. This results in a fast, culture-insensitive comparison where strings are ordered based only on their binary values. This option can't be combined with other <see cref="T:System.Globalization.CompareOptions" /> values and must be used alone.</summary>
</Docs>
</Member>
<Member MemberName="OrdinalIgnoreCase">
@@ -428,7 +455,7 @@
</ReturnValue>
<MemberValue>268435456</MemberValue>
<Docs>
<summary>String comparison must ignore case, then perform an ordinal comparison. This technique is equivalent to converting the string to uppercase using the invariant culture and then performing an ordinal comparison on the result.</summary>
<summary>Indicates that the string comparison ignores case and then performs an ordinal comparison. This is equivalent to converting both strings to uppercase using the invariant culture and then performing the comparison.</summary>
</Docs>
</Member>
<Member MemberName="StringSort">
@@ -472,7 +499,7 @@
</ReturnValue>
<MemberValue>536870912</MemberValue>
<Docs>
<summary>Indicates that the string comparison must use the string sort algorithm. In a string sort, the hyphen and the apostrophe, as well as other nonalphanumeric symbols, come before alphanumeric characters.</summary>
<summary>Indicates that the string comparison uses the string sort algorithm, where nonalphanumeric symbols (such as hyphens and apostrophes) are sorted before alphanumeric characters.</summary>
</Docs>
</Member>
</Members>