如何返回字符的Unicode 代码点?例如,如果输入是“A”,那么输出应该是“U+0041”。理想情况下,解决方案应该处理代理对。
代码点是指根据Unicode的实际代码点,它不同于代码单元(UTF8 有 8 位代码单元,UTF16 有 16 位代码单元,UTF32 有 32 位代码单元,在后一种情况下,值等于代码点,在考虑了字节序之后)。
如何返回字符的Unicode 代码点?例如,如果输入是“A”,那么输出应该是“U+0041”。理想情况下,解决方案应该处理代理对。
代码点是指根据Unicode的实际代码点,它不同于代码单元(UTF8 有 8 位代码单元,UTF16 有 16 位代码单元,UTF32 有 32 位代码单元,在后一种情况下,值等于代码点,在考虑了字节序之后)。
以下代码将string
输入的代码点写入控制台:
string input = "\uD834\uDD61";
for (var i = 0; i < input.Length; i += char.IsSurrogatePair(input, i) ? 2 : 1)
{
var codepoint = char.ConvertToUtf32(input, i);
Console.WriteLine("U+{0:X4}", codepoint);
}
输出:
U+1D161
由于 .NET 中的字符串是 UTF-16 编码的,因此char
构成字符串的值需要首先转换为 UTF-32。
很简单,因为 C# 中的字符实际上是 UTF16 代码点:
char x = 'A';
Console.WriteLine("U+{0:x4}", (int)x);
为了解决这些注释,char
C# 中的 A 是一个 16 位数字,并包含一个 UTF16 代码点。高于 16 位空间的代码点不能用 C# 字符表示。C# 中的字符不是可变宽度。然而,一个字符串可以有 2 个字符,每个字符都是一个代码单元,形成一个 UTF16 代码点。如果您有字符串输入和 16 位空间以上的字符,则可以使用char.IsSurrogatePair
and Char.ConvertToUtf32
,如另一个答案中所建议的:
string input = ....
for(int i = 0 ; i < input.Length ; i += Char.IsSurrogatePair(input,i) ? 2 : 1)
{
int x = Char.ConvertToUtf32(input, i);
Console.WriteLine("U+{0:X4}", x);
}
C# 不能将 unicode 代码点存储在 a 中char
,因为char
只有 2 个字节,并且 unicode 代码点通常会超过该长度。解决方案是将代码点表示为字节序列(作为字节数组或“扁平化”为 32 位原语)或字符串。接受的答案转换为 UTF32,但这并不总是理想的。
这是我们用来将字符串拆分为其 unicode 代码点组件的代码,但保留了原生 UTF-16 编码。结果是一个可用于在 C#/.NET 中本地比较(子)字符串的可枚举:
public class InvalidEncodingException : System.Exception
{ }
public static IEnumerable<string> UnicodeCodepoints(this string s)
{
for (int i = 0; i < s.Length; ++i)
{
if (Char.IsSurrogate(s[i]))
{
if (s.Length < i + 2)
{
throw new InvalidEncodingException();
}
yield return string.Format("{0}{1}", s[i], s[++i]);
}
else
{
yield return string.Format("{0}", s[i]);
}
}
}
}
在 .NET Core 3.0 或更高版本中,您可以使用Rune Struct:
// Note that and are encoded using surrogate pairs
// but A, B, C and ✋ are not
var runes = "ABC✋".EnumerateRunes();
foreach (var r in runes)
Console.Write($"U+{r.Value:X4} ");
// Writes: U+0041 U+0042 U+0043 U+270B U+1F609 U+1F44D
实际上@Yogendra Singh 的回答有一些优点,目前是唯一一个投反对票的人。可以这样完成工作
public static IEnumerable<int> Utf8ToCodePoints(this string s)
{
var utf32Bytes = Encoding.UTF32.GetBytes(s);
var bytesPerCharInUtf32 = 4;
Debug.Assert(utf32bytes.Length % bytesPerCharInUtf32 == 0);
for (int i = 0; i < utf32bytes.Length; i+= bytesPerCharInUtf32)
{
yield return BitConverter.ToInt32(utf32bytes, i);
}
}
经测试
var surrogatePairInput = "abc";
Debug.Assert(surrogatePairInput.Length == 5);
var pointsAsString = string.Join(";" ,
surrogatePairInput
.Utf8ToCodePoints()
.Select(p => $"U+{p:X4}"));
Debug.Assert(pointsAsString == "U+0061;U+0062;U+0063;U+1F4A9");
示例是相关的,因为一堆便便表示为代理对。
我在msdn 论坛上找到了一个小方法。希望这可以帮助。
public int get_char_code(char character){
UTF32Encoding encoding = new UTF32Encoding();
byte[] bytes = encoding.GetBytes(character.ToString().ToCharArray());
return BitConverter.ToInt32(bytes, 0);
}
public static string ToCodePointNotation(char c)
{
return "U+" + ((int)c).ToString("X4");
}
Console.WriteLine(ToCodePointNotation('a')); //U+0061