c# – 使用.Net的大于2个字节的unicode字符
我使用这个代码生成U 10FFFC
var s = Encoding.UTF8.GetString(new byte[] {0xF4,0x8F,0xBF,0xBC}); 我知道这是私人使用的,但它显示一个单一的字符,我期望显示它.操作这个unicode字符时出现问题. 如果我以后这样做: foreach(var ch in s) { Console.WriteLine(ch); } 而不是打印单个字符,它打印两个字符(即字符串显然由两个字符组成).如果我改变我的循环,将这些字符添加回一个空字符串,如下所示: string tmp=""; foreach(var ch in s) { Console.WriteLine(ch); tmp += ch; } 最后,tmp将只打印一个字符. 这里究竟发生了什么?我以为char包含一个unicode字符,我从来不必担心一个字符有多少个字节,除非我正在转换为字节.我的真实用例是,我需要能够检测到在字符串中使用非常大的unicode字符.目前我有这样的事情: foreach(var ch in s) { if(ch>=0x100000 && ch<=0x10FFFF) { Console.WriteLine("special character!"); } } 然而,由于这种分割非常大的角色,这不行.我该如何修改这项工作? 解决方法
U 10FFFC是一个Unicode代码点,但字符串的接口不会直接公开一系列Unicode代码点.它的接口暴露了一系列UTF-16代码单元.这是一个非常低级的文本视图.非常不幸的是,这样一个低级的文本视图被嫁接到最明显和直观的界面可用…我将尽量不要太多关于我不喜欢这样的设计,只是说不要紧多么不幸,这只是一个(悲伤的)事实,你必须住.
首先,我会建议您使用 var s = char.ConvertFromUtf32(0x10FFFC); 所以,这个字符串的长度不是1,因为正如我所说,接口处理UTF-16代码单元,而不是Unicode代码点. U 10FFFC使用两个UTF-16代码单元,所以s.Length是2. U FFFF以上的所有代码点都需要两个UTF-16代码单元来表示. 您应该注意ConvertFromUtf32不返回char:char是UTF-16代码单元,而不是Unicode代码点.为了能够返回所有Unicode代码点,该方法不能返回单个字符.有时它需要返回两个,这就是为什么它使它成为一个字符串.有时你会发现一些API处理int而不是char,因为int可以用于处理所有的代码点(ConvertFromUtf32作为参数,ConvertToUtf32是什么样的结果). 字符串实现IEnumerable< char>,这意味着当您迭代字符串时,每次迭代可获得一个UTF-16代码单元.这就是为什么迭代你的字符串并打印出来,会产生一些破坏的输出,其中有两个“东西”.那些是组成U 10FFFC表示的两个UTF-16代码单元.他们被称为“代理人”.第一个是高/中等代价,第二个是低/低代价.当您单独打印它们时,它们不会产生有意义的输出,因为单个代理在UTF-16中甚至无效,并且它们也不被视为Unicode字符. 当您将这两个代理附加到循环中的字符串时,您可以有效地重建代理对,并在以后打印该对,从而获得正确的输出. 在咆哮的前面,请注意,没有人抱怨在该循环中使用了畸形的UTF-16序列.它创建一个具有孤立代理的字符串,但是一切都没有发生:字符串类型甚至不是UTF-16格式的单元序列,而是UTF-16代码单元序列的类型. The static IEnumerable<int> AsCodePoints(this string s) { for(int i = 0; i < s.Length; ++i) { yield return char.ConvertToUtf32(s,i); if(char.IsHighSurrogate(s,i)) i++; } } 那么你可以像下面这样迭代: foreach(int codePoint in s.AsCodePoints()) { // do stuff. codePoint will be an int will value 0x10FFFC in your example } 如果您希望将每个代码点作为字符串,而不是将返回类型更改为IEnumerable< string>而收益行为: yield return char.ConvertFromUtf32(char.ConvertToUtf32(s,i)); 使用该版本,以下工作原样是: foreach(string codePoint in s.AsCodePoints()) { Console.WriteLine(codePoint); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |