第十四章 字符,字符串和文本处理

目录:

14.1 字符

14.2 System.String类型

14.3 高效率构造StringBuilder对象

14.4 获取对象的字符串表示:ToString

14.5 解析字符串来获取对象:Parse

14.6 编码:字符和字节的相互转换

14.7 安全字符串

14.1 字符

在.NET Framework中,字符总是表示成16为Unicode代码值。每个字符都是System.Char结构(一个值类型)的实例。

数值类型与Char实例相互转换:

转型(强制类型转换):效率最高,编译器会生成中间语言(IL)指令来执行转换,而且不必调用方法。

使用Convert类型:提供了几个静态方法来实现Char和数值类型的相互转换。

使用IConvertible接口:效率最差,使用方法需先将实例转换成IConvertible。需要装箱。

14.2 System.String类型

一个String代表一个不可变(immutalbe)的顺序字符串。

14.2.1 构造字符串

许多编程语言都将String视为基元类型-编译器允许在源代码中直接使用字面值字符串。

“逐字字符串”,在引号之间的所有字符都会被视为字符串的一部分。通常用于指定文件或目录的路劲,或者与正则表达式配合使用。

14.2.2 字符串时不可变的

 字符串不可变,意味着它允许在一个字符串上执行各种操作,而不实际更改字符串。

还意味着在操纵或访问字符串时不会发生线程同步问题。

CLR可通过一个String对象共享多个完全一致的String内容——从而节省内存——这就是所谓的“字符串留用”。

14.2.3 比较字符串

”比较“或许是最常见的字符串操作。一般因为两个原因要比较字符串:判断相等性或者排序。

排序时应该总是执行区分大小写的比较。原因是假如只是大小写不同的两个字符串被视为相等,那么每次排序都可能按不同顺序排序,用户会感到困惑。

接受CompareOption实参的方法要求显示传递语言文化。出于编程目的而比较字符串时,应该总是使用StringComparison.Ordinal或者StringComparison.OrdinalIgnoreCase。要以语言文化正确的方法来比较字符串,就应该使用StringComparison.CurrentCutrue或者StringComparision.CultureIgnoreCase。

以语言文化正确地方式比较字符串时,有时需要指定另一种语言文化,而不是使用与调用线程关联的那一种。 如:StartsWith,EndsWith,Compare方法的重载版本。

每个线程都关联两个特殊属性,每个属性都引用一个CultureInfo对象。

CurrentUICulture属性:该属性获取要向用户显示的资源。它标志了在显示UI元素时应使用的语言。

CurrentCulture属性:不适合使用CurrentUICulture属性的场合就使用该属性,例如数字和日期格式化,字符串大小写转哈以及字符组比较。

14.2.4 字符串留用

 如果应用程序经常对字符串进行区分大小写的序号比较,或者事先知道许多字符串对象都有相同的值,就可以利用CLR的字符串留用机制来显著提升性能。CLR初始化时会创建一个内部哈希表。在这个表中,键(key)是字符串,而值(value)是对托管堆中的String对象的引用。哈希表最开始是空的。

程序加载时,CLR默认留用程序集的元数据中描述的所有字面值字符串。

14.2.5 字符串池

 编译源代码时,编译器必须处理每个字面值字符串,并在托管模块的元数据中嵌入。同一个字符串在源代码中多次出现,把它们都嵌入元数据会使生成的文件无所谓地增大。许多编译器只在模块的元数据中只将字面值字符串写入一次。引用该字符串的所有代码都被修改成引用元数据中的一个字符串。编译器将单个字符串的多个实例合并成一个实例,能显著减少模块大小。

14.2.6 检查字符串中的字符和文本元素

System.Char实际代表一个16位Unicode码值,而且该值不一定就等于一个抽象Unicode字符。有的抽象Unicode字符是两个码值的组合(文本元素)。有的Unicode文本元素要求用两个16位值表示。第一个称为”高位代理项“,第二个称为”低位代理项“。高位代理项范围在U+D800到U+DBFF之间,低位代理范围在U+DC00到U+DFFF之间。

14.2.7 其他字符串操作

Clone,Copy,CopyTo,Substring,Tostring ...

14.3 高效率构造StringBuilder对象

 由于String类型代表不可变字符串,所以FCL提供了System.Text.StringBuilder类型对字符串和字符进行高效动态处理,并返回处理好的String对象。从逻辑上说,StringBuilder对象包含一个字段,该字段引用了由Char结构构成的数组。可利用StringBuilder的各个成员来操纵该字符串,高效率地缩短字符串或更改字符串中的字符。

14.3.1 构造StringBuilder对象

StringBuilder类的关键概念。

最大容量:一个Int32值,指定了能放到字符串中的最大字符串。默认值是Int32.MaxValue(约20亿)。

容量:一个Int32值,指定了由StringBuilder维护的字符串数组的长度。默认为16

字符数组:一个由Char结构构成的数组,负责维护”字符串“的字符内容。字符数总是小于或等于”容量“和”最大容量“值。

14.3.2 StringBuilder的成员

StringBuilder的大多数成员都能更改字符数组的内容,同时不会造成在托管堆上分配新对象。StringBuilder只有以下两种情况会分配新对象。

动态构造字符串,其长度超过了设置的”容量“。
调用StringBuilder的ToString方法

StringBuilder成员:

MaxCapacity:只读属性,返回字符串能容纳的最大字符数(最大容量)

Capacity:可读/可写属性,获取或设置字符串的长度(容量)。将容量设得比字符串长度或者比MaxCapacity大将抛出ArgumentOutOfRangeException异常

EnsureCapacity: 方法,保证字符数组至少具有指定的长度(容量)。如果传给方法的值大于StringBuilder的当前容量,当前容量会自动增大。如果当前容量已大于传给该属性的值,则不会发生任何变化。

Length:可读/可写属性,获取或设置”字符串“中的字符数。它可能小于字符串的当前容量。将这个属性设为0,会将StringBuilder的内容重置为空字符串。

ToStyring:方法,这个方法的无参版本返回代表StringBuilder的字符数组的一个String

Chars:可读/可写索引器属性,获取或设置字符数组知道指定索引位置的字符。

Clear:方法,清除StringBuilder对象的内容,等同于把它的Length属性设为0,

Append:方法,在字符数组末尾追加一个对象。如有必要,数组会进行扩充。

Insert:方法,在字符数组中插入一个对象。如有必要,数组会进行扩充。

AppendFormat:方法,在字符数组末尾追加指定的零个或多个对象,如有必要,数组会进行扩充。

ApendLine:方法,在字符数组末尾追加一个行中止符或者一个带行中止符的字符串:如有必要,会增大数组的容量。

Replace:方法,将字符数组中的一个字符替换成另一个字符,或者将一个字符串替换成另一个字符串。

Remove:方法,从字符数组中删除指定范围的字符。

Equals:方法,只有两个StringBuilder对象具有相同最大容量,字符数组容量和字符内容才返回true。

CopyTo:方法,将StringBuilder的字符内容的一个子集复制到一个Char数组中。

14.4 获取对象的字符串表示:ToString

任何类型想要提供合理的方式获取对象当前值的字符串表示,就应重写ToString方法。

 14.4.1 指定具体的格式和语言文化

无参ToString方法有两个问题。首先,调用者无法控制字符串的格式。其次,调用者不能方便地选择一种特定语言文化来格式化 字符串。为了对字符串格式进行更多的控制,你重写的ToString方法应该允许指定具体的格式和语言文化信息(实现System.IFormattable接口)。

对于大多数类型,调用ToString并为格式字符串传递null值完全等价于调用ToString并为格式字符串传递“G”。换言之,对象默认使用“常规格式”对自身进行格式化。字符串默认使用与调用线程关联的语言文化信息进行格式化。

IFormatProvider接口的基本思路是:当一个类型实现了该接口,就认为该类型的实例提供对语言文化敏感的格式信息,与调用线程关联的语言文化应被忽略。 

14.4.2 将多个对象格式化成一个字符串

可使用String静态方法Format

14.4.3 提供定制格式化器

 可以定义一个方法,在任何对象需要格式化成字符串的时候由StringBuilder的AppendFormat方法调用该方法。AppendFormat不是为每个对象调用Tostring,而是调用定制的方法,按照我们希望的任何方式格式化部分或全部对象。

14.5 解析字符串来获取对象:Parse

能解析字符串的任何类型都提供了公共静态方法Parse。方法获取一个string并返回类型的实例。

14.6 编码:字符和字节的相互转换

 Win32开发人员经常要写代码将Unicode字符和字符串转换成“多字节字符集”(Multi-ByteCharacter Set,MBCS)格式——繁琐,容易出错。在CLR中,所有字符都表示成16位Unicode码值,而所有字符串都由16位Unicode码值构成,这简化了运行时的字符和字符串处理。

如果想要将字符串保存到文件中,或者通过网络传输。可以将16位值编码成压缩的字节数组,以后再将字节数组解码回16位值得数组。这种编码技术还使托管应用程序能和非Unicode系统创建的字符串进行交互。

UTF-16将每个16位字符编码成2个字节。不对字符产生任何影响,也不发生压缩——性能非常出色。UTF-16编码也称为“Unicode编码”。UTF-16可用于从“低位优先”转换成“高位优先”,或者从“高位优先”转换成"低位优先"

UTF-8将部分字符编码成1个字节,部分编码成2个字节,部分编码成3个字节,在有部分编码成4个字节。值在0x0080之下的字节压缩成1个字节,适合表示美国使用的字符。0x0080-0x07FF的字符转换成2个字节,适合欧洲和中东语言。0x0800以及之上的字符转换成3个字节,适合东亚语言。最后,代理项对表示成4个字节。

UTF-7编码用于旧式系统。(字符可以使用7位值来,已经淘汰)

ASCII编码方案将16位字符编码成ASCII字符,也就是说,值小于0x0080的16位字符被转换成单字节。值超过0x007F的任何字符都不能被转换,否则字符的值会丢失。

GetPreamble:返回一个字节数组,指出在写入任何已编码字节之前,首先应该在一个流中写入什么字节。这些字节经常称为“前导码”或“字节顺序标记”字节。

Covert:将字节数组从一种编码(来源编码)转换位另一种(目标编码)。

Equals:如果从Encoding派生的两个对象代表相同的代码页和前导码设置,就返回true。

GetHashCode:返回当前Encoding实例的哈希码。

14.6.1 字符和字节流的编码和解码

字节流通常以数据块的形式传输。会造成数据损坏,是由于所有Encoding派生都不维护多个方法调用之间的状态。要编码或解码以数据块形式传输的字节/字符,必须进行一些些额外的工作来维护方法调用之间的状态,从而防止丢失数据。

字节块解码首先要获取一个Encoding派生对象引用,再调用其GetDecoder方法。

从Encoding派生的类型可用于无状态(中途不保持状态)编码和解码。从Decoder派生的类型只能用于解码。

14.6.2 Base-64字符串编码和解码

另一个流行的方案是将字节序列编码成Base-64字符串。

14.7 安全字符串

String对象在内存中包含一个字符数组。如果允许执行不安全或者非托管的代码,这些代码就可以扫描进程的地址空间,找到包含敏感数据的字符串,并以非授权的方式加以利用。即使String对象只有一小段时间进行垃圾回收,CLR也可能无法立即重用String对象的内存,致使String的字符长时间保留在进程的内存中(尤其是假如String对象是较老的一代),造成机密数据泄露。此外,由于字符串不可变,所以当你处理它们时,旧的副本会逗留在内存中,最终造成多个不同版本的字符串散布在整个内存空间中。

以下情况允许将SecureString作为密码传递。

与加密服务提供程序协作。

创建,导入或导出X。509证书。

在特定用户下启动新进程。

构造事件日志会话。

使用System。Windows.Controls.PasswordBox控件。

每天学习一丢丢
原文地址:https://www.cnblogs.com/terry-1/p/10133668.html