如何返回一个字符的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);
为了回应评论,C#中的char
是一个16位数字,可以保存UTF16编码点。超过16位空间的编码点无法用C#字符表示。C#中的字符不具备可变宽度。然而,字符串可以将两个跟随的字符作为代码单元,组成一个UTF16编码点。如果您有一个字符串输入并且包含超过16位空间的字符,您可以使用char.IsSurrogatePair
和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);
}
'a'
) 是 U+0061
,大写字母 A ('A'
) 是 U+0041
。 - Esailija// 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
C#中的char
无法存储Unicode代码点,因为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]);
}
}
}
}
实际上,@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");
这个例子是相关的,因为“狗屎”被表示为代理对。
char
作为参数,这意味着它永远无法给你超过两个字节的信息。而你的改进非常大,因为你实际上解析了一个字符串,而不是字符。 - Chris我在MSDN论坛上找到了一个小方法。希望这能帮到你。
public int get_char_code(char character){
UTF32Encoding encoding = new UTF32Encoding();
byte[] bytes = encoding.GetBytes(character.ToString().ToCharArray());
return BitConverter.ToInt32(bytes, 0);
}
(int)character
以外的结果?如果 character
是代理对的前半部分,会发生什么? - dtbUTF32Encoding
,但由于该方法只接受一个char
,因此它没有任何效果,与(int) character
相同,但比强制转换慢得多。实际上,character.ToString().ToCharArray()
将始终返回一个仅包含一个项目(大小为2个字节)的数组,并且BitConverter
永远不会返回大于65535的值。原则上是个好主意,但以这种方式呈现是无用的。 - Abelpublic static string ToCodePointNotation(char c)
{
return "U+" + ((int)c).ToString("X4");
}
Console.WriteLine(ToCodePointNotation('a')); //U+0061
'a'
) 是 U+0061
,大写字母 A ('A'
) 是 U+0041
。 - EsailijaChar.IsSurrogate(c)
,则应该抛出异常,因为这样的代码单元不能被视为代码点值,因此没有代码点表示法。 - Tom Blodget