第十四章 字符、字符串和文本处理
- .NET Framework中字符总是表示成16位Unicode代码值,Char类型提供两个公共只读常量字段MaxValue(\0)和MinValue(\uffff)
- 数值类型与Char的转换
- 强制类型转换(效率高),C#中可以指定checked或unchecked
- 使用System.Convert,转换以checked方式执行
- 使用IConvertible接口(效率最差),例:ToChar,ToInt32
- String
- String派生自Object是引用类型,但不允许使用new操作符构造String
- String对象永远在堆上(需要垃圾回收),对非字面值使用+操作符,会在堆上创建多个String对象
- 不建议在字符串中硬编码换行符(\n),使用Environment.NewLine,该属性对平台敏感(例如Windows下换行符是\r\n)
- 字符串不可变,在字符串上执行各种操作返回新字符串:操作和访问字符串时不会出现线程同步问题
- CLR可通过一个String对象共享多个完全一样的字符串
- 比较字符串:推荐使用Equals,Compare,StartWith,EndWith方法
- 字符串留用
- 比较两个字符串相等性也是一个耗时的方法,可以利用字符串留用机制
- CLR初始化时创建一个内部哈希表,key是字符串,value是对托管堆中字符串的引用
- 使用Intern方法获取一个String, 如果在哈希表中已存在则返回该字符串的引用,没有再创建
- 使用IsInterned方法获取String,如果不存在时返回null
- 除非显式调用了Intern方法,否则不能以字符串留用为理由使用ReferenceEquals方法判断相等性
- 注意留用本身也是需要耗时的
- 字符串池:源码中的相同字面值的字符串,只被写入元数据一次
- Char代表16位的Unicode值,有些字符需要两个16位值表示,此时应该使用StringInfo类进行处理(Char的数量不一定等于字符串长度)
- 复制字符串或一部分:Clone、ToString返回this,Copy返回复制(不常用),CopyTo将字符串的一部分复制到数组,SubString代表字符串一部分的新字符串
- 使用StringBuilder高效率构造字符串
- StringBuilder维护一个可自动扩容的Char数组,使用ToString时再转换成String
- StringBuilder最大容量默认为Int32;容量默认为16,若超过则自动倍增;Char数组,初始值为0
- 使用ToString获取对象的字符串表示
- 无参ToString方法:无法控制字符串格式;无法选择特定语言文化
- 实现IFormattable接口String ToString(String format, IFormatProvider formatProvider),其中format指定应该如何格式化对象,formatProvider提供语言文化信息;例如DateTime类型,d表示短日期,D表示长日期
- formatProvider一般用于数字(例如转换成当地的货币格式)
- 将多个对象格式化成一个字符串
- 使用{数字}指示Format方法将{数字}替换成第数字个参数,在内部,对每个对象调用ToString方法, 然后再拼接成一个字符串
- 在大括号内可以指定格式信息,例String.Format(“{0:D}”,time)
- 或者使用StringBuilder的AppendFormat方法构造
- 提供定制格式化器:格式化时对每个对象不调用ToString方法,而是指定的方法(实现ICustomFormatter)
- 定义String Format (String format, object arg, IFormatProvider formatProvider)
- StringBuilder在调用AppendFormat方法时,第一个参数传入一个IFormatProvider,如果其中也定义了ICustomFormatter,就会调用接口中定义的Format 方法
- 使用Parse解析字符串来获取对象(类中定义一个公共静态方法Parse,可能抛出异常)
- 要将字符串保存到文件,或者通过网络传输,需要将16位Char压缩成字节数组
- UTF-16:每个字符编码成2字节,对Char不做任何处理
- UTF-8:每个字符根据范围转换成1~4个字节
- 使用Encodding类的静态属性或者GetEncoding方法获取一个派生自Encoding类的对象,然后使用GetBytes方法将字符串或字符数组转换成字节数组
- 对于网络传输,例如传输UTF-16编码的字节流,若从流中分两次读取到5个和7个字节,两次调用Encoding的GetString可能会获得错误的值(5->2个字符,7->3个字符,但是传输的12个字节代表6个字符)。可以使用GetDecoder方法获取一个Decoder对象,如果字节数组包含的字节不足以完成一个字符,将会输入数据流中未完全解析的字符,直到包含足够的字节以解码完整的字符。
- 使用System.Convert下的FromBase64String和ToBase64String方法可以使用Base64编码。
- 安全字符串:传统的字符串在内存中是明文存储的,并且生命周期不确定。SecureString在内存中保存的字符会自动加密,而且以非托管内存块存储,使用Dispose会对缓冲区的内容进行清零