【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类型后面加上了d
和D
来指定相应的显示格式。通常一个指定的格式化字符串通过:
紧跟在相应类型后面。
2.DateTime类型支持一系列的不同格式字符输出——例如,t
用来显示一个短时间格式(short time format)而T
则显示的是一串长时间格式(long time format),同理还有g
和G。
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】扩展资料
- StringBuilder扩容机制
- C# CultureInfo中常用的InvariantCulture
- 标准日期和时间格式字符串中的RoundTripKind
- double和string之间的RoundTrip
- ExplicitCapture仅显式捕获
参考网址:https://www.cnblogs.com/zenronphy/p/ProfessionalCSharp7Chapter9.html#95-%E5%B0%8F%E7%BB%93