之前在处理文本的时候遇到过这样的一个问题,有的字,它看着是一个,但是程序说他是两个,但是实际真的是一个。 好吧,你们一定没有听懂我在讲什么。没关系一起来看看代码
假如有这么一个字符串“黄腾霄好瘦哦”,需要使用程序找出这个字符串包含几个字,怎么找?
var s=“黄腾霄好瘦哦”;
var len=s.Length;
很简单是不是。那再看看这个字符串,“黄腾霄也能算瘦🤔”,不出意料的话应该是8个字对吧?
我们看看上一个程序的输出。
惊了,他居然输出了长度为9。
实际上这个地方的问题出在最后一个emoji上。
让我们先看看这个字符串的Unicode编码是什么样的。
我们看到这个8个字符
的字符串实际上包含了9个Unicode。
而其中整个emoji字符🤔,实际是由2个Unicode字符拼接而成的。
实际上对于“U+D800-U+DFFF”中的值是作为代理字符对存在的,他们会将两个字符映射成为一个字符。
所以在Unicode编码上是2个,而显示上却只有一个。而我们的String.Length恰好就只是读Unicode编码的个数。
所以才会出现多一个的情况。
那么怎么办呢?我们看看下面这个代码
var s = @"黄腾霄也能算瘦🤔";
var len = s.Length;
var info = new StringInfo(s);
var realLength = info.LengthInTextElements;
成功!!StingInfo
可以获取字符串实际显示的字符个数。
当然这样还不够,我们还是会想要枚举字符串中每个字符。
不过SringInfo并不是集合,也没有继承IEnumerable
的接口
但是我们可以通过静态方法StringInfo.GetNextTextElement
获得指定位置的显示字符
或者通过静态方法StringInfo.GetTextElementEnumerator
获得指定字符串的显示字符迭代器。
我们看看如下代码
var s = @"黄腾霄也能算瘦🤔";
var len = s.Length;
var info = new StringInfo(s);
var realLength = info.LengthInTextElements;
Console.WriteLine(s);
for (int i = 0; i < realLength; i++)
{
Console.WriteLine(StringInfo.GetNextTextElement(s, i));
}
Console.WriteLine("-----------");
var enumerator = StringInfo.GetTextElementEnumerator(s);
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.GetTextElement());
}
我们看到每个显示字符都成功迭代了。(PS:console下字体无法识别emoji字符,所以会使用??来显示,但是枚举方法是对的)
参考文献:
本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/%E4%BD%BF%E7%94%A8StringInfo%E6%AD%A3%E7%A1%AE%E6%9F%A5%E6%89%BE%E5%AD%97%E7%AC%A6%E4%B8%AA%E6%95%B0.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。