先推荐两个正则的工具:
正则表达式是用于匹配字符串中字符组合的模式,也就是根据我们设定的匹配规则在一串字符串中,获取到指定的字符串; 比如:
const re = /ab+c/; // 可以匹配到 abc, abbc, abbbc等
根据 正则表达式可视化 可以看出, 可以匹配到 b的个数 在 1个以上, 那么 abc, abbc, abbbc
都是符合要求的
当然 abbcc
也是可以匹配的, 因为abbc
是符合 /ab+c/
的要求的; 也是 符合 我们刚刚描述的: 根据我们设定的匹配规则在一串字符串中,获取到指定的字符串
了解了正则的基本的概念, 那么就学习 正则表达式;
表现形式
在js中,正则表达式 表现形式 有两种方式:
- 字面量: 由斜杠(/)包围而不是引号包围,
const re = /ab+c/i; // i 表示忽略大小写
- 构造函数: 使用
RegExp
对象,const re = new RegExp("ab+c", 'i')
标志参数
在 const re = /ab+c/i;
中有一个 i
, 这是正则表达式的标志, 表示 忽略大小写, 还有其他的标志
标志 | 描述 |
---|---|
g | 全局搜索。 |
i | 不区分大小写搜索。 |
m | 多行搜索。 |
s | 允许 . 匹配换行符。 |
u | 使用unicode码的模式进行匹配。 |
y | 执行“粘性(sticky )”搜索,匹配从目标字符串的当前位置开始。 |
简单模式
所谓的简单模式,就是正则直接由你想找的字符构成,比如: abcdedf
这个字符串, 你想找到 cde
这个子字符串, 那么正则直接可以写 /cde/
, 这就是简单模式, 比较暴力,但是有时候也是有价值的
特殊字符
相对于简单模式, 使用特殊字符就表现的更高级了。
比如:abbbbbcd
这个字符串, 你想找到 abbbbbc
这个子字符串, 你可以直接用简单字符去写,但是会觉得麻烦不是?
可以采用 特殊字符 进行匹配, 比如: /ab+c/
, +
表示 匹配 一个或者一个以上的字符, 在这里就是 匹配 一个或者一个以上的b
断言
表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。
断言的组成之一是边界。对于文本、词或模式,边界可以用来表明它们的起始或终止部分(如向前断言,向后断言以及条件表达式)。
边界类断言
字符 | 含义 |
---|---|
^ | 匹配输入的开头。比如 /^A/ 匹配不了 "an A" 里面的 "A",但是可以匹配 "An A" 里面第一个 "A"。 |
$ | 匹配输入的结束。比如 /t$/ 不能匹配 "eater" 中的 "t",但是可以匹配 "eat" 中的 "t"。 |
\b | 匹配一个单词的边界,这是一个字的字符前后没有另一个字的字符位置, 例如在字母和空格之间。需要注意的是匹配的单词边界不包括在匹配中。换句话说,匹配字边界的长度为零。一些例子: /\bm/ 在 "moon" 中匹配到 "m" |
\B | 匹配非单词边界。这是上一个字符和下一个字符属于同一类型的位置:要么两者都必须是单词,要么两者都必须是非单词,例如在两个字母之间或两个空格之间。字符串的开头和结尾被视为非单词。与匹配的词边界相同,匹配的非词边界也不包含在匹配中。例如,/\Bon/ 在 “at noon” 中匹配 “on” ,/ye\B/ 在 "possibly yesterday"中匹配"ye" |
其他断言
字符 | 含义 | |
---|---|---|
x(?=y) | 向前断言: x 被 y 跟随时匹配 x。例如,对于/Jack(?=Sprat)/ ,“Jack”在跟有“Sprat”的情况下才会得到匹配.`/Jack(?=Sprat | Frost)/` “Jack”后跟有“Sprat”或“Frost”的情况下才会得到匹配。不过, 匹配结果不包括“Sprat”或“Frost”。 |
x(?!y ) | 向前否定断言: x 没有被 y 紧随时匹配 x。例如,对于/\d+(?!.)/ ,数字后没有跟随小数点的情况下才会得到匹配。对于/\d+(?!.)/.exec(3.141) ,匹配‘141’而不是‘3’。 | |
(?<=y)x | 向后断言: x 跟随 y 的情况下匹配 x。例如,对于/(?<=Jack)Sprat/ ,“Sprat”紧随“Jack”时才会得到匹配。对于`/(?<=Jack | Tom)Sprat`,“Sprat”在紧随“Jack”或“Tom”的情况下才会得到匹配。不过,匹配结果中不包括“Jack”或“Tom”。 |
(?<!y)x | 向后否定断言: x 不跟随 y 时匹配 x。例如,对于/(?<!-)\d+/ ,数字不紧随-符号的情况下才会得到匹配。对于/(?<!-)\d+/.exec(3) ,“3”得到匹配。 而/(?<!-)\d+/.exec(-3) 的结果无匹配,这是由于数字之前有-符号。 |
字符类
区分不同类型的字符,例如区分字母和数字。
字符 | 含义 |
---|---|
. | 匹配除行终止符之外的任何单个字符 |
\d | 匹配任何数字(阿拉伯数字), 0-9 |
\D | 匹配任何非数字(阿拉伯数字)的字符 |
\w | 匹配一个单字字符(字母、数字或者下划线) |
\W | 匹配任何不是来自基本拉丁字母的单词字符 |
\s | 匹配一个空白字符,包括空格、制表符、换页符和换行符 , [ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff] |
\S | 匹配非空白字符 |
\t | 匹配一个水平制表符 (U+0009) |
\r | 匹配一个回车符 (U+000D) |
\n | 匹配一个换行符 (U+000A) |
\v | 匹配一个垂直制表符 (U+000B) |
\f | 匹配一个换页符 (U+000C) |
[\b] | 匹配退格键 |
\0 | 匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 \0<digits> 是一个八进制转义序列。 |
\cX | 当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符 |
\xhh | 匹配一个两位十六进制数(\x00-\xFF)表示的字符 |
\uhhhh | 匹配一个四位十六进制数表示的 UTF-16 代码单元 |
\u{hhhh} or \u{hhhhh} | 仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符 |
\ | 转义字符 |
组和范围
表示表达式字符的分组和范围
字符 | 含义 |
---|---|
x|y | 匹配 "x" 或 "y" 任意一个字符 |
[xyz] 或者 [a-c] | [xyz] 匹配 "x", "y" 或者 "z" 任意一个字符, [a-c] 匹配 a到c的这个范围内的任意字符 |
[^xyz] 或者 [^a-c] | 匹配不是 这些字符 |
(x) | 分组 |
\n | 其中n是一个正整数, 对正则表达式中与n括号匹配的最后一个子字符串的反向引用(计算左括号), 例如,/apple(,)\sorange\1/ 匹配 “apple,orange,cherry,peach” 中的 "apple,orange,", 其中 \1 引用了 之前使用 () 捕获的 |
(?<Name>x) | 具名捕获, 匹配"x"并将其存储在返回的匹配项的groups属性中,该属性位于<Name> 指定的名称下。尖括号(< 和 > ) 用于组名,例如'web-doc'.match(/-(?<customName>\w)/).groups // {customName: "d"} |
(?:x) | 非捕获组, 匹配 “x”,但不记得匹配。不能从结果数组的元素中收回匹配的子字符串 |
量词
表示匹配的字符或表达式的数量。
字符 | 含义 |
---|---|
x* | 将前面的项“x”匹配0次或更多次 |
x+ | 将前一项“x”匹配1次或更多次 |
x? | 将前面的项“x”匹配0或1次 |
x{n} | 其中“n”是一个正整数,与前一项“x”的n次匹配 |
x{n,} | 其中,“n”是一个正整数,与前一项“x”至少匹配“n”次 |
x{n,m} | 其中,“n”是0或一个正整数,“m”是一个正整数,而m > n至少与前一项“x”匹配,最多与“m”匹配 |
x*? , x+? , x?? , x{n}? , x{n,}? , x{n,m}? | 默认情况下,像 * 和 + 这样的量词是“贪婪的”,这意味着它们试图匹配尽可能多的字符串。?量词后面的字符使量词“非贪婪”:意思是它一旦找到匹配就会停止 |
使用范例
58. 最后一个单词的长度
function lengthOfLastWord(s: string): number {
const regx: RegExp = /\b([^\s]*)\s*$/ig
const res = regx.exec(s)
return res === null ? 0 : res[1].length
};
2129. 将标题首字母大写
function capitalizeTitle(title: string): string {
return title.toLowerCase().replace(/\b([a-z]{3,})/ig, (input, char) => {
return char[0].toUpperCase() + char.substring(1)
})
};
剑指 Offer 05. 替换空格
function replaceSpace(s: string): string {
return s.replace(/\s/ig, '%20');
};
8. 字符串转换整数 (atoi)
function myAtoi(s: string): number {
const reg = /^\s*([+-]?\d+)/
const result = s.match(reg)
const t:number = result ? Number(result[1]) : 0
return Math.max(-1 * 2 ** 31, Math.min(2 ** 31 - 1 , t))
};