wei*_*i37 145 .net c# string unicode unicode-string
这段代码:
string a = "abc";
string b = "AC";
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);
Run Code Online (Sandbox Code Playgroud)
输出:
Length a = 3
Length b = 4
Run Code Online (Sandbox Code Playgroud)
为什么?我唯一能想到的是中文字符长度为2个字节,并且该.Length方法返回字节数.
Ada*_*ppe 232
其他人都给出了表面答案,但也有更深层次的理由:"字符"的数量是一个难以定义的问题,计算起来可能非常昂贵,而长度属性应该很快.
为什么难以定义?嗯,有几个选项,没有一个比另一个更有效:
代码单元的数量(字节或其他固定大小的数据块; C#和Windows通常使用UTF-16,因此它返回两个字节的数量)肯定是相关的,因为计算机仍然需要处理该形式的数据出于多种目的(写入文件,例如,关心字节而不是字符)
Unicode代码点的数量相当容易计算(虽然O(n)因为你必须扫描代理对的字符串)并且可能对文本编辑器很重要....但实际上与字符数不同印在屏幕上(称为字素).例如,一些带重音的字母可以用两种形式表示:单个代码点,或两个点配对在一起,一个代表字母,另一个说"添加重音到我的伴侣信".这对是两个字还是一个?您可以规范化字符串以帮助解决此问题,但并非所有有效字母都具有单个代码点表示.
即使字素的数量与打印字符串的长度不同,这取决于其他因素的字体,并且由于某些字符在许多字体(字距调整)中打印有一些重叠,因此字符串在屏幕上的长度无论如何,不一定等于字素长度的总和!
有些Unicode点不是传统意义上的字符,而是某种控制标记.像字节顺序标记或从右到左的指示符.这些算吗?
简而言之,字符串的长度实际上是一个非常复杂的问题,计算它可能需要大量的CPU时间以及数据表.
而且,重点是什么?为什么这些指标很重要?好吧,只有你可以回答你的情况,但就个人而言,我发现它们通常是无关紧要的.我发现限制数据输入更符合逻辑上的字节限制,因为无论如何都需要传输或存储.显示器侧软件可以更好地限制显示器尺寸 - 如果您有100个像素的消息,您所适合的字符数取决于字体等,无论如何数据层软件都不知道.最后,考虑到unicode标准的复杂性,如果你尝试其他任何东西,你可能会在边缘情况下遇到错误.
因此,这是一个很难通用的问题.代码单元的数量很容易计算 - 它只是底层数据数组的长度 - 并且作为一般规则最有意义/最有用,具有简单的定义.
这就是为什么b长度4超出表面解释"因为文档说的如此".
Hab*_*bib 32
索引1中的角色"AC"是SurrogatePair
要记住的关键点是代理对代表32位 单个字符.
您可以尝试此代码,它将返回 True
Console.WriteLine(char.IsSurrogatePair("AC", 1));
Run Code Online (Sandbox Code Playgroud)
Char.IsSurrogatePair方法(String,Int32)
true如果s参数包括位置index和index + 1的相邻字符,并且位置索引处字符的数值范围为U + D800到U + DBFF,位置索引+ 1处字符的数值范围为U + DC00到U + DFFF; 否则,false.
这在String.Length属性中进一步解释:
Length属性返回此实例中Char对象的数量,而不是Unicode字符数.原因是Unicode字符可能由多个Char表示.使用System.Globalization.StringInfo类来处理每个Unicode字符而不是每个Char.
dee*_*see 23
正如其他答案所指出的那样,即使有3个可见字符,它们也用4个char对象表示.这就是Length4而不是3的原因.
MSDN声明
Length属性返回此实例中Char对象的数量,而不是Unicode字符数.
但是,如果您真正想知道的是"文本元素"的数量,而不是Char您可以使用StringInfo该类的对象数量.
var si = new StringInfo("AC");
Console.WriteLine(si.LengthInTextElements); // 3
Run Code Online (Sandbox Code Playgroud)
您还可以枚举这样的每个文本元素
var enumerator = StringInfo.GetTextElementEnumerator("AC");
while(enumerator.MoveNext()){
Console.WriteLine(enumerator.Current);
}
Run Code Online (Sandbox Code Playgroud)
foreach在字符串上使用会将中间的"字母"拆分为两个char对象,并且打印结果将不对应于字符串.
phu*_*clv 10
正如其他人所说,它不是字符串中的字符数,而是Char对象的数量.该字符是代码点U + 20213.由于该值超出了16位char类型的范围,因此它以UTF-16编码为代理对D840 DE13.
在其他答案中提到了获得字符长度的方法.但是应该谨慎使用,因为可以有很多方法来表示Unicode中的字符."à"可以是1个组合字符或2个字符(a +变音符号).可能需要标准化,就像twitter一样.
您应该阅读
绝对最低限度每个软件开发人员绝对必须知道的Unicode和字符集(没有借口!)
这是因为length()仅适用于不大于的Unicode代码点U+FFFF.这组代码点称为基本多语言平面(BMP),仅使用2个字节.
其外部的Unicode代码点BMP使用4字节代理对以UTF-16表示.
要正确计算字符数(3),请使用 StringInfo
StringInfo b = new StringInfo("AC");
Console.WriteLine(string.Format("Length 2 = {0}", b.LengthInTextElements));
Run Code Online (Sandbox Code Playgroud)
好的,在.Net和C#中,所有字符串都编码为UTF-16LE.A string存储为一系列字符.每个char封装2个字节或16位的存储.
我们在"纸上或屏幕上"看到的单个字母,字符,字形,符号或标点符号可以被视为单个文本元素.如Unicode标准附件#29 UNICODE TEXT SEGMENTATION中所述,每个文本元素由一个或多个代码点表示.可以在此处找到详尽的代码列表.
每个代码点需要编码为二进制,以供计算机进行内部表示.如上所述,每个char存储2个字节.等于或低于的代码点U+FFFF可以存储在一个代码中char.上面的代码点U+FFFF存储为代理对,使用两个字符表示单个代码点.
鉴于我们现在知道我们可以推断出,文本元素可以存储为一个char,作为两个字符的代理对,或者如果文本元素由多个代码点表示单个字符和代理对的某种组合.好像这不够复杂,一些文本元素可以用代码点的不同组合来表示,如Unicode标准附件#15,UNICODE NORMALIZATION FORMS中所述.
插曲
因此,渲染时看起来相同的字符串实际上可以由不同的字符组合组成.两个这样的字符串的序数(逐字节)比较将检测差异,这可能是意外的或不期望的.
您可以重新编码.Net字符串.这样他们就可以使用相同的规范化表格.归一化后,具有相同文本元素的两个字符串将以相同的方式编码.为此,请使用string.Normalize函数.但是,请记住,一些不同的文本元素看起来彼此相似.:-s
那么,这个问题对于这个问题意味着什么?文本元素''由单个Code Point U + 20213 cjk统一表意文字扩展名b表示.这意味着它不能编码为单个char,必须使用两个字符编码为代理对.这就是为什么string b一个char更长的原因string a.
如果你需要可靠(参见警告)计算一个文本元素的数量,string你应该使用这样的
System.Globalization.StringInfo类.
using System.Globalization;
string a = "abc";
string b = "AC";
Console.WriteLine("Length a = {0}", new StringInfo(a).LengthInTextElements);
Console.WriteLine("Length b = {0}", new StringInfo(b).LengthInTextElements);
Run Code Online (Sandbox Code Playgroud)
给出输出,
"Length a = 3"
"Length b = 3"
Run Code Online (Sandbox Code Playgroud)
正如所料.
警告
StringInfo和TextElementEnumerator类中的Unicode文本分段的.Net实现通常应该是有用的,并且在大多数情况下,将产生调用者期望的响应.但是,正如Unicode标准附件#29中所述,"匹配用户感知的目标并不总是能够完全满足,因为单独的文本并不总是包含足够的信息来明确地确定边界."
| 归档时间: |
|
| 查看次数: |
20235 次 |
| 最近记录: |