字符串
字符串
基本操作
合并
显然最简单的是用+
直接合并,但用concat
函数也可以实现拼接操作:
let s_plus = "Hello "+"World!";
let s_concat = "Hello ".concat("World!")
let s_concat_mult = "Hello ".concat("My ","name ", "is ","tom.");
>s_plus
"Hello World!"
>s_concat
"Hello World!"
>s_concat_mult
"Hello My name is tom."
注意concat
函数是一个参数可变长度的函数,因此可以加任意多个。 一般我们很少用这个函数,直接用+
运算符会方便很多
大小写转换
函数toLowerCase
和toUpperCase
函数可以将字符串转成小写和大写:
>console.log("Hello".toLowerCase());
hello
>console.log("Hello".toUpperCase());
HELLO
搜索
indexOf函数
函数indexOf
可以定位子串在字符串中首次出现的位置:
let first_tom = "Hello tom.".indexOf("tom");
first_tom
6
下面这个表格有助于你理解这个函数是如何运作的:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
H | e | l | l | o | t | o | m | . | |
^ |
注意下标的计算从0开始。 如果搜索不到,那么会返回-1
let not_found = "Hello tom.".indexOf("Tom");
not_found
-1
显然indexOf
区分大小写。
思考一下
怎么不区分大小写判断子串首次出现的位置?
函数indexOf
可以带一个额外参数。这个参数指明从何处开始搜索:
console.log("Tiger Tiger Tiger".indexOf("Tiger"));
0
console.log("Tiger Tiger Tiger".indexOf("Tiger",1));
6
console.log("Tiger Tiger Tiger".indexOf("Tiger",7));
12
参数 | 结果 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
T | i | g | e | r | T | i | g | e | r | T | i | g | e | r | ||||
("Tiger") | 0 | >> ^ | ||||||||||||||||
("Tiger",1) | 6 | >> | ^ | |||||||||||||||
("Tiger",7) | 12 | >> | ^ |
显然indexOf("xxx",0) == indexOf("xxx")
思考一下
如何统计一个子串在母串中出现的次数
lastIndexOf函数
函数lastIndexOf
从后往前搜索,返回子串最后一次出现的位置:
console.log("Tiger Tiger Tiger".lastIndexOf("Tiger"));
12
console.log("Tiger Tiger Tiger".lastIndexOf("Tiger",11));
6
console.log("Tiger Tiger Tiger".lastIndexOf("Tiger",5));
0
参数 | 结果 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
T | i | g | e | r | T | i | g | e | r | T | i | g | e | r | ||||
("Tiger") | 0 | ^ | << | |||||||||||||||
("Tiger",11) | 6 | ^ | << | |||||||||||||||
("Tiger",7) | 12 | ^ | << |
子串
你可以从某个字符串里截取一段形成新的字符串:
substring( begin ,end );
这个函数会截取从 范围的字符串形成一个新串。注意前者是闭区间,所以包括begin
,后者是开区间,因此不包括end
。这也是大多数语言在这种情况下的标准处理方式。
>console.log("Hello".substring(1, 4));
ell
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
H | e | l | l | o |
开始 | 结束 不包括4 |
执行的结果从下标1开始,一直到4为止,其中4不包括,前闭后开的区间是编程语言处理类似问题的常用方法。
slice( begin, end )
这个函数和substring
类似,都是 截取从范围的字符串形成一个新串。但这个函数接收负数作为输入。substring
虽然也接收负数,但会把所有负数作为0处理。
而slice
函数将负数视为从后往前计算,最后一个字符是-1,倒数第二个是-2,倒数第三是-3,以此类推。
>console.log("Hello".slice(-4,-1));
ell
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
-5 | -4 | -3 | -2 | -1 |
H | e | l | l | o |
开始 | 结束 不包括-1 |
substr(begin length)
这个函数的行为和前两个函数都不同,他的第二个参数是长度,也就是从begin
开始,截取length
长度的字符串。
>console.log("Hello".substr(1,3));//从下标1开始,截取3个字符。
ell
substr
第一个参数也可以是是负数,代表从后往前数。当截取长度超过字符串长度时,只截取到字符串的尾部结束。
>console.log("Hello".substr(3,5));
lo
因为从下表开始截取两个字符就到字符串尾部了,所以这里返回的字符串只有两个字符。
替换和分割
replace
replace
函数用来替换子串:
>console.log("Hello Tom".replace("Tom","Jerry"));
"Hello Jerry"
通过replace把"Tom"
替换成了"Jerry"
。 显然这个函数大小写敏感。
split
这个函数我们已经学过而且用过了,不过这个函数可以带一个额外的参数:
>console.log("1,2,3,4,5,6,7".split(","));
[ "1", "2", "3", "4", "5", "6", "7" ]
>console.log("1,2,3,4,5,6,7".split(",",3));
["1","2","3"]
不带后面的参数,就会分割后全部放入数组后输出,因此你获得7个元素。 如果带后面的参数3,将会只输出前3个元素。
正则表达式(了解)
有些人面对问题时会想:我知道,应该用正则表达式解决问题,这下他就有两个问题了。——Jamie Zawinski
更复杂的需求
indexOf
、replace
可以做简单的字符串替换,但如果你有比较复杂的要求,他们就不能满足要求了。
想一下下面的要求:
- 检查用户输入手机号码的合法性,电话号码有11位数字,第一位一定以1开始。
- 检查用户输入邮箱的合法性,邮箱必须以一个用户名开始,中间有一个
@
符号,后面跟一个域名,域名必须是xxxx.xxx
这种形式,第一个词是主域名,只能包含数字字母下划线和减号,后面可以有一个或多个.xxxx
,只能包含数字和字母。比如:123@netease.com
、helpme@sina.com.cn
等等。 - 用户输入日期,检查其合法性,日期必须是如
2019-12-06
或2019-12-6
或2019/12/06
以及2019/12/6
这种形式的。 - js的变量名,只能包含大小写字母、下划线、数字和$符号,第一个字符只能是字母、下划线和$符号。
这些要求都不是简单的字符串表示方法可以满足的要求,用正则表达式则可以很方便处理这些问题。
比如上文的要求3判断用户日期的要求,我们可以这样写:
>let reg = /\d{4}[-/]\d{1,2}[-/]\d{1,2}/;
>console.log("2019-12-06".search(reg));
0
>console.log("2019/12/6".search(reg));
0
>console.log("2019.12.06".search(reg));
-1
第一个字符串匹配,第二个也匹配,但第三个不匹配
这里的/\d{4}[-/]\d{1,2}[-/]\d{1,2}/
就是我们编写的正则表达式,然后我们通过字符串的search
函数来寻找匹配这个正则表达式的子串的位置,类似于indexOf
。
这个表达式的意思是,4个数字(\d{4}
)接一个-/
二选一([-/]
),再接1或者2个数字(\d{1,2}
),再接一个-/
二选一,最后接1个或2个数字(\d{1,2}
)。
search
可以接受正则表达式作为输入,并像indexOf
一样返回其位置。
此外replace
函数,也可以根据正则表达式进行替换。
学习材料
正则表达式是处理字符串的利器,虽然你需要(大量的)额外学习,但这个学习是值得的。
不过我们的课程因为篇幅所限,并不准备详细介绍它。
如果你想学习,简明教程可以看正则表达式-教程和正则表达式30分钟入门教程。
(哦,不过是30分钟嘛,小case,你一定这么想)
接下来你可以看这本书来更好地掌握它。
(哦,我的上帝,看看这500多页的篇幅,你确定真的能看完它吗?)。
正如我在很多教程里说过的,学习正则表达式最好的方式是大量使用它。 所以如果你现在很难掌握它,只能说明你目前没有这样的需求(换句话说,你目前写的功能太low,还用不上这种高级货)。
重要的是保证你记得有这个工具,并在需要的时候重新学习他就可以了。这不是正是大学教育的真髓嘛。