《CLR via C#》 字符、字符串和文本处理

字符

字符总是表示成16位Unicode代码值,每个字符都是System.Char接口(值类型)的实例。

Sytem.Char

方法

方法名 说明
GetUnicodeCategory 返回UnicodeCategory枚举,表明该字符是由Unicode标准定义的控制字符、货币符号、小写字母、大写字母、标点符号还是其他字符。
ToLowerInvariant 忽略语言文化将字符转换位小写
ToLower 转换小写,但会使用与调用线程关联的语言文化信息(System.Threading.Thread的静态属性CurrentCulture)
Equals 两个Char实例代表同一个16位Unicode码位的前提下返回true
CompareTo 两个Char实例忽略语言文化的比较结果
GetNumericValue 返回字符的数值形式

Char实例的相互转换

  • 转型(强制类型转换):是效率最高的,因为编译器会生成中间语言指令来执行转换,而且不必调用方法。
  • 使用Convert类:System.Convert提供了几个静态方法来实现Char和数值类型的转换。所有转换都以checked方式执行,发现转换将造成数据丢失就会抛出OverflowException异常。
  • 使用IConvertible接口:效率最差,因为再值类型上调用接口方法会装箱。而且很多是显式实现的接口。

System.String

字符串构造

C#将String视为基元类型,也就是允许再源代码中直接使用字面值(literal)字符串。编译器将这些字符串放到模块的元数据中,并在运行时加载和引用它们。

逐字字符串(verbatim string):用@来声明字符串,其字符串中所有的字符都视为一部分。下面的代码在元数据中生成同样的字符串,但是逐字字符串可读性更好。

1string file = "C:\\Windows\\System32\\Notepad.exe";
2string file = @"C:\Windows\System32\Notepad.exe";

字符串是不可变的

字符串一经创建便不能更改。使字符串不可变有几点好处

  • 允许对字符串进行操作,但不实际更改字符串。
  • 在操纵或访问字符串时不会发生线程同步问题。
  • 可通过一个String对象共享多个一致的String内容,从而节省内存——字符串留用(string interning)。

比较字符串

判断字符串相等性方法:

  • Equals
  • Compare
  • StartsWith
  • EndsWith

出于变成目的比较字符串时,应该用StringComparsion.Ordinal或者StringComparison.OrdinalIgnoreCase。忽略语言文化比较最快。

要以语言文化来比较字符串,就应该用StringComparsion.CurrentCulture或者StringComparison.CurrentCultureIgnoreCase

注意

应该用String.ToUpperInvariant来进行正规化(normalizing)。因为编译器对执行大写比较的代码有优化

注意

CompareTo默认执行对语言文化敏感的比较,而Equals执行普通的序号比较

语言文化的字符串比较

System.Globalization.CultureInfo类表示一个“语言/国家”对。在CLR中每个线程都关联了两个特殊属性,每个属性都引用一个CultureInfo对象。

  • CurrentUICulture属性:获取要向用户显式的资源。多用于GUI或Web窗体中。
  • CurrentCulture属性:不适合CurrentUICulture属性的场合就使用该属性。

字符串留用

CLR初始化时会创建一个内部哈希表。键是字符串,而值是对托管堆中String对象的引用。

String类提供了两个方法,便于你访问这个哈希表

  • Intern方法获取一个String,获得它的哈希码。并在内部检查是否有匹配。有就返回当前引用,无则创建字符串副本,并将副本添加到哈希表中,返回对其的引用。
  • IsIntern方法获取一个String,获得它的哈希码。如果哈希表中没有匹配则返回null。

字符串池

编译器只在模块的元数据中只将字面值字符串写入一次。引用该字符串的所有代码都被修改成引用元数据中同一个字符串。编译器也将当个字符串的多个实例合并成一个实例,显著减少模块大小。

利用StringBuilder高效率构造字符串

StringBuilder对象包含一个字段,该字段引用了由Char结构构成的数组。可利用StringBuilder的成员来高效率的操纵该数组。如果字符串变大,超过了预先分配的大小,则会自动分配一个新的、更大的数组,复制字符,并开始使用新数组,前一个数组会被垃圾回收。

ToString方法

System.Object定义了一个publicvirtual、无参的ToString方法。这个方法代表对象当前值的字符串,而且应该根据语言文化进行格式化。

调试器中变量上方出现的数据提示的文本就是通过调用对象的ToString方法来获取的

编码

  • UTF-16(Unicode):将每16位字符编码成2个字节。不对字符产生影响,也不发生压缩————性能出色。
  • UTF-8:值在0x0080之下的字符压缩成1字节,0x0080~0x07FF转换成2字节。0x0800以上位4字节。代理项对表示成4字节。0x0800以上效率不如UTF-16。
  • UTF-32:使用4字节来编码所有字符。
  • ASCII:将16位字符编码范围只有0x00~0x7F