C#高级编程第11版

【1】9.1 System.String 类

String类中关键的方法。如替换,比较等。

【2】9.1.1 构建字符串

1.String类依然有一个缺点:因为它是不可变的数据类型,这意味当你初始化一个string对象后,这个对象不会再次发生任何改变,这个设计使得你在试图多次重复修改某个字符串的时候非常的低效(inefficient)。

2.当使用+=添加一串新的字符串时,实际上这个对象将引用新的引用地址,原来那个会被回收清理。

3.ASCII码自加1加密。

4.通过StringBuilder你仅仅只能追加或者移除字符串中的某些内容,然而,它却对文本处理有非常好的性能提升。

5.StringBuilder类含有两个主要属性:

  • Length:标识它已包含的string的长度。
  • Capacity:标识它初始所能容纳的string的长度。

7.StringBuilder(“enjoy”,Capacity);

.当你想操作字符串的时候,你可以使用StringBuilder,而当你想存储或者显示最终结果时,你可以使用String对象。

【3】9.1.2 StringBuilder 成员

1.StringBuilder可以只传一个初始字符串,也可只指定它的初始容量。

2.还有一个只读的MaxCapacity属性,来标识一个StringBuilder实例最大能够存储多少字符。

var sb = new StringBuilder(capacity: 100, maxCapacity: 500);

3.你也可以在之后任何时候显式地设置它的容量,虽然当你设置的容量小于当前字符串实际长度的时候,会得到一个异常:

var sb = new StringBuilder("Hello");
sb.Capacity = 100;

4.StringBuilder的主要方法:Append(追加),AppendFormat(格式化并追加),Insert,Remove,Replace,ToString(将当前StringBuilder保存的字符串输出为一个String对象。)

5.StringBuilder和String之间没有任何类型转换(不管是显式的还是隐式的)。

【4】9.2.1 字符串插值

1.添加$前缀允许包含在一对大括号里的占位符(placeholder)引用代码中的结果。实际上,这里只是一个语法糖。

2.在$前缀修饰的字符串中你并不仅仅只能使用变量,你也可以调用任何带有返回值的方法:

string s2 = $"Hello, {s1.ToUpper()}";
string s2 = String.Format("Hello, {0}", s1.ToUpper());//实际上它被转换成了

3.也可以在字符串中应用多个变量:

int x = 3, y = 4;
string s3 = $"The result of {x} + {y} is {x + y}";
string s3 = String.Format("The result of {0} and {1} is {2}", x, y, x + y);//实际上是

【5】9.2.1.1 可格式化的字符串

1.格式化字符串中定义好了结果串(normal string)中各个接收插入串(interpolated)的位置。这种方式定义了一种格式化属性,用来返回格式化后的结果串(the resulting format string),这种属性称之为ArgumentCount,并且你可以通过GetArgument方法来返回格式串中定义的Argument,如下面所示:

int x = 3, y = 4;
//FormattableString是这种字符串的返回类型
FormattableString s = $"The result of {x} + {y} is {x + y}";
Console.WriteLine($"format: {s.Format}");
for (int i = 0; i < s.ArgumentCount; i++)
{
    Console.WriteLine($"argument {i}: {s.GetArgument(i)}");
}

运行结果如下所示:

format: The result of {0} + {1} is {2}
argument 0: 3
argument 1: 4
argument 2: 7

按位置分别取值。

2.FormattableString类需要.NET 4.6的支持。

【6】9.2.1.2 使用其他区域进行格式化

第一行的Console.WriteLine中调用的是会根据区域化显示不同内容的字符串,而第二行则不管你在地球的哪个角落,输出的都是统一格式的字符串:

var day = new DateTime(2025, 2, 14);
Console.WriteLine($"{day:d}");
Console.WriteLine(Invariant($"{day:d}"));

欧美地区:

2/14/2025
02/14/2015

中国大陆:

2025/2/14
02/14/2025

也可以直接使用系统提供的Invariant方法,这样你就不用自己每次都写一个了:

Console.WriteLine(FormattableString.Invariant($"{day:d}"));

【7】9.2.1.3 忽略大括号

如果你需要在格式化字符串中保留大括号以及里面的变量名,你可以通过使用两个大括号来避免它被格式化,如下所示:

string s = "Hello";
Console.WriteLine($"{{s}} displays the value of s: {s}");

【8】9.2.2 日期时间和数字的格式

1.在DateTime类型后面加上了dD来指定相应的显示格式。通常一个指定的格式化字符串通过:紧跟在相应类型后面。

2.DateTime类型支持一系列的不同格式字符输出——例如,t用来显示一个短时间格式(short time format)而T则显示的是一串长时间格式(long time format),同理还有gG。

3.为数字指定格式化字符串时大小写并没有任何影响。

4.为数字指定格式化字符串时大小写并没有任何影响,n表示按3位一组进行输出,e表示使用指数计数法(exponential notation),x表示转换成16进制,而c则是以货币的格式(currency)进行输出

【9】9.2.3 自定义字符串格式

当遇见格式化字符F时,仅输出FirstName,而遇到L时则显示LastName,A则表示输出与ToString一样的全名。为了实现这一需求,你可以使用IFormattable接口。

通过重写Tostring方法来实现你所需要的。

【10】9.3 正则表达式

可以把正则表达式当成一种小型的程序设计语言,它实现一个特定的目的:在一个大的字符串中定位子串。

【11】9.3.1 正则表达式概述

而通过正则表达式,大量的代码可以被压缩至短短数行。通常来讲(Essentially),你会实例化一个RegEx对象(或者仅仅调用静态的RegEx方法),将要处理的字符串作为参数传递给它,然后按照实际需求编写好正则表达式。

【12】9.3.2 RegularExpressionsPlayground 示例

1.部分RegexOptions枚举中的细节:

成员名描述
CultureInvariant 忽略与特定区域相关的字符串。
ExplicitCapture 修改Match类的收集方式,确认只有显式命名的子串才是有效捕获内容。
IgnoreCase 忽略输入串的大小写。
IgnorePatternWhitespace 从字符串中移除所有非转义的空格,并且允许使用英镑或者哈希记号的注释。
Multiline 修改^和$的定义,使得它们可以对每一行起效,而非仅应用于整个串。
RightToLeft 对输入串启用从右到左搜索,默认是从左到右。
Singleline 指定单行模式,这意味着.将会匹配每一个字符。

2.元字符,这是一些由之后紧跟的字符组成的转义序列,带有特殊的含义。

3.S*就代表着任意数量的字符,只要它们不是空格就行。

4.用[]包裹相应的字符,代表着可选字符的匹配请求。

5.[0-9]的快捷记法是d,假如你想搜索一个整数,这意味着它可能包括至少1位数字字符,你可以这么写:[0-9]+或者[d]+。

6.^在中括号里也有不同的含义,当它处于中括号外侧的时候,它代表着文本的第一个字符,但当它处于中括号中的时候,它代表的是非其后的字符,例如[^0]代表匹配0以外的任意字符。

7.WriteMatches方法前后各补5个字符。

【13】9.3.3 显示结果

WriteMatches方法中大部分致力于将找到的匹配串扩展成尽可能长的显示串。

【14】9.3.4 匹配、分组和捕获

1.在C#语言里,你可以将任意数量的语句放置在一组大括号中,结果会被当成一个复合语句进行输出。

2.在正则表达式的模式(pattern)中,你可以将任意数量的字符(包括元字符和转义序列)进行分组,它们会被当成一个单一字符,唯一的区别就是在正则表达式中你使用的是小括号而已。结果序列(resultant sequence)被当成一个组进行处理。

3.+计量符号仅仅只能针对前面的一个字符,如果有小括号,那么针对的就是把小括号里的字符串当成一个字符去匹配。

4.假如一组可能的匹配里会有交集,那么默认会输出里面最长的匹配序列。如bananas里的anan而非单独的两个an。

5.解析URI的协议,地址和端口,可以这么写表达式:

(https?)(://)([.w]+)([s:]([d]{2,5})?)

6.用了Match.Groups属性来遍历整个Group对象并且将每个结果的索引和值输出。

7.正则表达式在分组前面以?<name>的形式指定分组的名称。使用?:来忽略某个分组。

8.?紧跟在s之后说明s出现的次数要么是0次还么是1次。(w代表字母),+表示这些字符可以重复若干次。(s代表空格)。内置分组[d]{2,5}d表示的是数字,其后的{2,5}表示的是前面的字符可以是最少2位,最多5位。

9.Regex类里面提供了一个方法GetGroupNames来获取表达式的分组名称。

【15】9.4 字符串和Span

Span<T>在内部其实是使用了ref关键字来保持对string的引用。通过Slice方法可以得到string的子串,该方法有两个参数,第一个参数标识的是起始位置,我们通过在text文本中定位Visual字样得到,第二个参数是子串长度,我们这里传递的是13,意思是从Visual的V开始读取13个字符赋值给slice,结果同样也是ReadOnlySpan<Char>类型。只有当你调用ToArray方法时才会重新给它分配所需的内存(allocates memory needed by the slide),这个方法得到的char数组我们传递给string的构造函数,以此来创建一个新的string。

【16】9.5 小结

string类型的重要性。StringBuilder类提升性能。正则表达式快速的检索和验证你的字符串。Span结构体来更加高效地操作string,它无需重新分配和释放内存。

【17】扩展资料

参考网址:https://www.cnblogs.com/zenronphy/p/ProfessionalCSharp7Chapter9.html#95-%E5%B0%8F%E7%BB%93

原文地址:https://www.cnblogs.com/wazz/p/14168500.html