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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,89 +1,64 @@
// <snippet2>

Check failure on line 1 in snippets/cpp/VS_Snippets_CLR_System/system.Globalization.CompareOptions.StringSort/CPP/compareoptions_stringsort.cpp

View workflow job for this annotation

GitHub Actions / snippets-build

ERROR: Project missing. A project (and optionally a solution file) must be in this directory or one of the parent directories to validate and build this code.
#include <iostream>
#using <System.dll>

// The following code example shows how sorting with CompareOptions::StringSort differs
// from sorting with->Item[Out] CompareOptions::StringSort.
// <snippet1>
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Globalization;

// __gc public class SamplesCompareOptions {
ref class MyStringComparer: public IComparer
ref class StringSort
{
public:
static void Main()
{
auto wordList = gcnew List<String^> {
"cant", "bill's", "coop", "cannot", "billet", "can't", "con", "bills", "co-op"
};

// Constructs a comparer using the specified CompareOptions.
CompareInfo^ myComp;
CompareOptions myOptions;
MyStringComparer( CompareInfo^ cmpi, CompareOptions options )
: myComp( cmpi ), myOptions( options )
{}
Console::WriteLine("Before sorting:");
for each (String^ word in wordList)
{
Console::WriteLine(word);
}

// Compares strings with the CompareOptions specified in the constructor.
virtual int Compare( Object^ a, Object^ b )
{
if ( a == b )
return 0;
Console::WriteLine(Environment::NewLine + "After sorting with CompareOptions::None:");
SortAndDisplay(wordList, CompareOptions::None);

if ( a == nullptr )
return -1;
Console::WriteLine(Environment::NewLine + "After sorting with CompareOptions::StringSort:");
SortAndDisplay(wordList, CompareOptions::StringSort);
}

if ( b == nullptr )
return 1;
private:
static void SortAndDisplay(List<String^>^ unsorted, CompareOptions options)
{
// Create a copy of the original list to sort.
auto words = gcnew List<String^>(unsorted);
// Define the CompareInfo to use to compare strings.
CompareInfo^ comparer = CultureInfo::InvariantCulture->CompareInfo;

String^ sa = dynamic_cast<String^>(a);
String^ sb = dynamic_cast<String^>(b);
if ( sa != nullptr && sb != nullptr )
return myComp->Compare( sa, sb, myOptions );
// Sort the copy with the supplied CompareOptions then display.
words->Sort(gcnew Comparison<String^>([comparer, options](String^ str1, String^ str2) {
return comparer->Compare(str1, str2, options);
}));

throw gcnew ArgumentException( "a and b should be strings." );
}
for each (String^ word in words)
{
Console::WriteLine(word);
}
}
};

int main()
int main(array<System::String ^> ^args)
{

// Creates and initializes an array of strings to sort.
array<String^>^myArr = {"cant","bill's","coop","cannot","billet","can't","con","bills","co-op"};
Console::WriteLine( "\nInitially, " );
IEnumerator^ myEnum = myArr->GetEnumerator();
while ( myEnum->MoveNext() )
{
String^ myStr = safe_cast<String^>(myEnum->Current);
Console::WriteLine( myStr );
}


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

// Sorts the array without StringSort.
Array::Sort( myArr, myComp );
Console::WriteLine( "\nAfter sorting without CompareOptions::StringSort:" );
myEnum = myArr->GetEnumerator();
while ( myEnum->MoveNext() )
{
String^ myStr = safe_cast<String^>(myEnum->Current);
Console::WriteLine( myStr );
}


// Sorts the array with StringSort.
myComp = gcnew MyStringComparer( CompareInfo::GetCompareInfo( "en-US" ),CompareOptions::StringSort );
Array::Sort( myArr, myComp );
Console::WriteLine( "\nAfter sorting with CompareOptions::StringSort:" );
myEnum = myArr->GetEnumerator();
while ( myEnum->MoveNext() )
{
String^ myStr = safe_cast<String^>(myEnum->Current);
Console::WriteLine( myStr );
}
StringSort::Main();
return 0;
}

/*
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 will be the following:

Initially,
Before sorting:
cant
bill's
coop
Expand All @@ -94,7 +69,7 @@
bills
co-op

After sorting without CompareOptions::StringSort:
After sorting with CompareOptions.None:
billet
bills
bill's
Expand All @@ -105,7 +80,7 @@
coop
co-op

After sorting with CompareOptions::StringSort:
After sorting with CompareOptions.StringSort:
bill's
billet
bills
Expand All @@ -116,4 +91,4 @@
con
coop
*/
// </snippet1>
// </snippet2>
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// <snippet1>

Check failure on line 1 in snippets/cpp/VS_Snippets_CLR_System/system.Globalization.CompareOptions.Values/CPP/compareoptions_values.cpp

View workflow job for this annotation

GitHub Actions / snippets-build

ERROR: Project missing. A project (and optionally a solution file) must be in this directory or one of the parent directories to validate and build this code.
#include <iostream>
#include <string>

using namespace System;
using namespace System::Globalization;

public ref class CompareOptionsExample
{
public:
static void 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);
}

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

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

int main(array<System::String ^> ^args)
{
CompareOptionsExample::Main();
return 0;
}

/*
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.
*/
// </snippet1>
Original file line number Diff line number Diff line change
@@ -1,67 +1,52 @@
// The following code example shows how sorting with CompareOptions.StringSort differs from sorting without CompareOptions.StringSort.

// <snippet1>
// <snippet2>
using System;
using System.Collections;
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 Main()
{
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.
var 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 will be the following:

Initially,
Before sorting:
cant
bill's
coop
Expand All @@ -72,7 +57,7 @@ This code produces the following output.
bills
co-op

After sorting without CompareOptions.StringSort:
After sorting with CompareOptions.None:
billet
bills
bill's
Expand All @@ -93,6 +78,5 @@ This code produces the following output.
co-op
con
coop

*/
// </snippet1>
// </snippet2>
Loading
Loading