Six digit unicode escaped value comparison

2019-02-18 14:03发布

问题:

I have a six digit unicode character, for example U+100000 which I wish to make a comparison with a another char in my C# code.

My reading of the MSDN documentation is that this character cannot be represented by a char, and must instead be represented by a string.

a Unicode character in the range U+10000 to U+10FFFF is not permitted in a character literal and is represented using a Unicode surrogate pair in a string literal

I feel that I'm missing something obvious, but how can you get the follow comparison to work correctly:

public bool IsCharLessThan(char myChar, string upperBound)
{
    return myChar < upperBound; // will not compile as a char is not comparable to a string
}

Assert.IsTrue(AnExample('\u0066', "\u100000"));
Assert.IsFalse(AnExample("\u100000", "\u100000")); // again won't compile as this is a string and not a char

edit

k, I think I need two methods, one to accept chars and another to accept 'big chars' i.e. strings. So:

public bool IsCharLessThan(char myChar, string upperBound)
{
    return true; // every char is less than a BigChar
}

public bool IsCharLessThan(string myBigChar, string upperBound)
{
    return string.Compare(myBigChar, upperBound) < 0;
}

Assert.IsTrue(AnExample('\u0066', "\u100000));
Assert.IsFalse(AnExample("\u100022", "\u100000"));

回答1:

To construct a string with the Unicode code point U+10FFFF using a string literal, you need to work out the surrogate pair involved.

In this case, you need:

string bigCharacter = "\uDBFF\uDFFF";

Or you can use char.ConvertFromUtf32:

string bigCharacter = char.ConvertFromUtf32(0x10FFFF);

It's not clear what you want your method to achieve, but if you need it to work with characters not in the BMP, you'll need to make it accept int instead of char, or a string.

As per the documentation for string, if you want to iterate over characters in a string as full Unicode values, use TextElementEnumerator or StringInfo.

Note that you do need to do this explicitly. If you just use ordinal values, it will check UTF-16 code units, not the UTF-32 code points. For example:

string text = "\uF000";
string upperBound = "\uDBFF\uDFFF";
Console.WriteLine(string.Compare(text, upperBound, StringComparison.Ordinal));

This prints out a value greater than zero, suggesting that text is greater than upperBound here. Instead, you should use char.ConvertToUtf32:

string text = "\uF000";
string upperBound = "\uDBFF\uDFFF";
int textUtf32 = char.ConvertToUtf32(text, 0);
int upperBoundUtf32 = char.ConvertToUtf32(upperBound, 0);
Console.WriteLine(textUtf32 < upperBoundUtf32); // True

So that's probably what you need to do in your method. You might want to use StringInfo.LengthInTextElements to check that the strings really are single UTF-32 code points first.



回答2:

From https://msdn.microsoft.com/library/aa664669.aspx, you have to use \U with full 8 hex digits. So for example:

string str1 = "\U0001F300";
string str2 = "\uD83C\uDF00";
bool eq = str1 == str2;

using the :cyclone: emoji.