第 6 讲:数据类型(三):字符和字符串
字符和字符串是 C# 里广泛使用的一种专用表示“只用来呈现原封不动的数据”的数据类型。字符是 char
关键字表示的,它的 BCL 名称是 System.Char
,表示一个单独的字符;而字符串是表示一系列字符构成的序列,用 string
关键字表示,它的 BCL 名称是 System.String
。
下面我们来看一下基本的赋值方式和书写格式。
Part 1 字符字面量和字符串字面量
我们先来说字符。字符就是一个单独的原始数据。
C# 里使用单引号来表达 a
是一个字符。
当然,一个数字字符和一个数字是有区别的。比如说 '3'
和 3
虽然,如下的写法都是可以输出一个字符 3 的:
和 C 语言不同,C# 的字符是包含中文汉字、日语假名等等符号的。比如说:
在 C 语言里,一个字符是只占一个字节的,因此它只能表达一个很简单的字符;汉字、日文甚至别的一些符号并不属于标准 ASCII 码里的内容,因此无法用一个字符来表示。但 C# 里是可以的。
这就是为什么,字符没办法参与计算了。
顺带一说,这里以单引号引起来的内容称为字符字面量(Character Literal)。
Part 2 字符串字面量
显然,一个单独的字符并不能表达很多的信息,因此大多数时候我们都会使用字符串(String)来表示一个字符序列,以达到描述复杂信息的功能。
字符串字面量(String Literal),当然,有些时候也简称字符串或者串。
C# 贴心地为我们提供了 Console.WriteLine
方法,可以让我们使用前面的所有类型,全部内嵌到小括号里参与输出,因此,这些字符串依然可以写进去。
空字符串
这样的话,emptyString
就是一个空的字符串,里面没有任何字符。当然,空字符串你也可以写成 String.Empty
或 string.Empty
前文稍微提到过,
string
是关键字,而String
是 BCL 名称。它们的区别仅仅是“BCL 名需要引入System
Part 3 原义字符串和转义字符
由于双引号在编程的时候有特殊用途(表示字符串字面量的开头和结尾),所以很明显,我们并不能在字符串字面量里使用引号。如果偏要输出引号的话,我们必须在左边添加反斜杠:\"
。这个行为称为转义(Escape)。那么理所应当地,这里带反斜杠的字符就是转义字符(Escape Character)了。
在 C 语言里,
\"
和\'
都是转义字符,即双引号里不可以直接出现单引号;但 C# 里是允许的。
转义字符除了上面说的双引号以外,还有一些别的。比如说制表符。制表符占据 8 个空格的空间。如果是写入字符串的时候,我们可以直接插入制表符:“ ”,但这样显得很不正常,因此 C# 里提供了一个字符写法:\t
,这就表示一个制表符:
最后,由于反斜杠本身作为转义字符的开始,因此我们单纯要输出一个反斜杠的时候,必须双写它。
我们目前就只需要接触这几个就可以了。后续用到新的转义字符的时候,我们再作出说明。
但是有些时候,我们要写一大段的文字(很有可能自带换行)。这个时候,字符串怎么写呢?我们采用的办法是通过原义字符串(Verbatim String)来搞定。
为了避免字符串里出现的特殊字符,C# 提供了一种字符串:
如果是一个很普通的字符串,就必须双写反斜杠来表示一个反斜杠字符。当我们在字符串最开头追加原义标记 @
后,字符串就成了原义字符串。原义字符串的内部除了双引号以外的其它所有字符都可以随便用了:不管你怎么写,原义字符都不作处理。
\"
这种写法会失效。所以,此时用到的是双写:""
。我们双写双引号,就表示原义字符串里的一个双引号字符。
总结一下:
普通字符串里,
\\
表示一个反斜杠字符,\"
表示一个双引号字符,\t
表示制表符(还有别的,这里不作介绍);原义字符串里,
""
表示一个双引号字符。
Part 4 字符串的长度
由于字符串是不定长的,因此它拥有长度(Length)的概念。字符串可以很长,它的长度是所有字符的总数。比如说,"こんにちは、お元気ですか。"
字符串里,有 9 个假名、2 个日语汉字和 2 个标点符号,因此长度是 13。
当然了,空字符串长度为 0,这个是不用多说的。
Part 5 字符串的基本操作
说起字符串,就不得不提一下字符串的基本操作。
不得不说,这些内容有点超纲,但是既然重要我们就得先说。超纲内容也不一定难,可能仅仅就是超前说明而已。
5-1 获取字符串长度
我们直接使用 .Length
的语法来表示和获取字符串的具体长度:
这样的话,输出和显示的就是 s.Length
这个东西。s
是字符串,后直接跟上 .Length
则会得到字符串的长度。前文说过,字符串的长度就是所有字符总数,因此这个字符串是 10 个字符,因此结果是 10,输出的内容也是 10。
顺带一提,
s.Length
的结果是一个数字,那么它会是什么类型的呢?对了,int
类型的。因为int
在 C# 里起到很重要的作用,因此很多地方都会使用int
,即使我们知道长度是不可能为负数的,按道理应该用uint
,但因为为了兼容性(底层,比如说和 C 语言以及别的没有无符号数据类型的语言进行交互的时候),int
是最合适的一种类型。
5-2 获取特定位置上的字符
我们采用类似 C 语言的中括号语法,可以获取一个字符串里指定位置上的字符是什么。
[]
语法来确定和获取 s
字符串里的字符信息。中括号的数字是 n,那么就取的是第 (n + 1) 个字符。换句话说,n 最小是 0,而不是 1。
这个例子里,s[3]
就相当于取的是 s
这个字符串里的第四个字符('l'
),因此,c
变量得到的结果就是 'l'
,最后输出的也是这个字符。
但请注意,你不能修改字符串的内容。虽然 C 语言里,你可以使用索引器来接受一个字符,以达到修改的目的,但 C# 里,整个字符串一旦声明后,就无法修改:
5-3 拼接字符串
有些时候我们可能需要拼接多个字符串,然后把这些字符串合并成一个字符串。我们需要用到的是一个叫 Concat
的方法。
这个例子应该比较好理解。我们使用 string.Concat
方法,把所有需要拼接在一起的字符串挨个顺次写进去,用逗号隔开;然后最后得到的结果就是整体的结果了。此时,用 result
变量接受结果。显示出来就是 Hello, Mike!
。
5-4 查看字符串是不是包含一个字符或字符串
如果一个字符串较长,我们可能会去查找里面的字符。比如说一个电话号码(用字符串表示后),我们需要查看是不是包含 666 这个序列。那么,我们可以这么写:
我们在字符串字面量(或变量)的后面追加 .Contains("666")
bool
的结果,赋值给 contains666
变量。
看到了吧,这里就用上了
bool
类型。
当然,小括号里不一定非得是序列,也可以是一个单独的字符:
5-5 查看字符串开头和结尾是不是固定的序列
如果我们要查看一个用字符串表达的电话号码里是不是以 13 开头的话,我们需要追加 .StartsWith("13")
来表示:
同理,如果要看字符串结尾是不是固定的序列,则使用 .EndsWith(序列)
表示:
这个依然也可以判断一个单独的字符:
5-6 比较字符串的具体序列是不是完全一样
如果要比较字符串是不是完全一致的话,我们用的是 string.Equals
:
5-7 查看字符串里指定字符(或字符串序列)的具体位置
.IndexOf(内容)
。
5-8 删掉一个字符或字符串
要想把字符串里的一部分完整序列去掉,我们用的是 .Remove(位置)
。
这表示从第 3 个位置的字符开始,后面的字符我们都不要了。所以 t
变量的结果是 "He"
。
.Remove(2, 2)
表示从第 3 个字符开始删,删掉 2 个字符。所以最后 t
结果是 "Heo"
。
要想替换掉序列的话,我们可以用 .Replace(字符, 字符)
或 .Replace(字符串, 字符串)
。
u
变量结果自然就是 "今儿天气好"
这样就变成了 "明儿天气好"
了。
要想取一部分字符,我们用 .Substring(开始位置, 取的长度)
来获取:
t
从第 1 个字符开始取,取 4 个字符,所以 t
结果是 "Hell"
。
Part 6 不可变的字符串
我们看到前面的这些操作,我们发现共同点:我们发现怎么去操作字符串,最后原始的字符串都是没有变动的:即使要修改字符串,变动的结果也会通过赋值给到新的变量上去,但原始的字符串并没有变化。这是 C# 里字符串的一大特殊性质:不可变(Immutable)。
比如这个例子,我们已经删掉了 s
的字符,但代码运行起来后,我们可以看到的是,s
还是 "Hello"
,而 t
才是 "He"
。
Part 7 总结
本节我们学习了字符和字符串的内容,以及操作。再怎么说,我们都不必考虑类似 C 语言那样字符串操作的复杂细节。所以从这个角度来说,C# 还是比较简单的。