字符
简单字符
简单字符指的是数字、字母、标点等,如1,2,3,a,b,c,用来代表一个字符
/a/ 表示匹配字母a
需要注意的是有些符号在正则中有特殊意义,已经不能算是简单字符了,比如 * 表示重复0次或多次,这时候如果我们想匹配 *就需要使用转义
/\*/ 表示匹配字符*
/\\\n/ 表示匹配字符串\n
元字符
正则表达式规定的一些特殊代码,多用来代表一类字符
/\w/ 表示匹配字母或数字或下划线或汉字
字符 | 描述 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
区间
字符 | 描述 |
---|---|
[0-9] | 匹配 0-9 之间的数字 |
[A-Z] | 匹配 A-Z 之间的字母 |
[157] | 匹配 1 5 7 |
重复
上面讲得都是一个字符,这里我们介绍一下如何重复一个字符
\b\w{6}\b 表示匹配刚好6个字符的单词
字符 | 描述 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
反义
有时需要查找不属于某个能简单定义的字符类的字符。这时需要用到反义
字符 | 描述 |
---|---|
\W | 匹配非字母、数字、下划线 |
\S | 匹配任何非空白字符 |
\D | 匹配一个非数字字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
分支条件
其实就是用|把不同的规则分隔开
举例:\d{5}-\d{4}|\d{5}
这个表达式会匹配用连字号间隔的9位数字或者5位数字
下面介绍高级用法
分组
用
()
括起来的就是一个分组
举例 var reg=/(\w)-(\d)/
(\w)就是分组1
(\d)就是分组2
捕获与反捕获
我们可以通过
\1
\2
来引用搜索分组匹配的文本
\b(\w+)\b\s+\1\b 可以匹配hi hi, 或者 nice nice
如果我们不需要捕获某个分组,则可以用
(?:)
var reg=/(?:\w)-(\d)/ 表示不捕获(?:\w),那么(\d)就是分组1
前向查找
前向查找是用来限制后缀的
字符 | 描述 |
---|---|
(?=exp) | 匹配exp前面的位置 |
(?!exp) | 匹配后面跟的不是exp的位置 |
举例: \b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc
\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字
后向查找
后向查找与前向查找相反,是用来限制前面的
字符 | 描述 |
---|---|
(?<=exp) | 匹配exp后面的位置 |
(?<!exp) | 匹配前面不是exp的位置 |
举例: (?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading
(?<![a-z])\d{7}匹配前面不是小写字母的七位数字
贪婪与懒惰
正则表达式通常匹配尽可能多的字符
举例:a.*b
将会匹配acbab整个字符串
有时,我们更需要匹配尽可能少的字符, 只需要加上一个问号?
举例:a.*?b
,如果把它应用于acbab的话,将会匹配acb
字符 | 描述 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
具名组匹配
ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31
解构赋值写法
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
one // foo
two // bar
字符串替换时,使用$<组名>引用具名组
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
// '02/01/2015'
引用
如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
运用
介绍常用api的注意事项
String#search
- 大小写敏感
- search() 方法不执行全局匹配,它将忽略标志 g。它同时忽略 regexp 的 lastIndex 属性,并且总是从字符串的开始进行检索,这意味着它总是返回 stringObject 的第一个匹配的位置。
var str="Well Done"
str.search(/Done/) // 5
str.search(/done/) // -1 大小写敏感
str.search(/done/i) // 5 大小写敏感
String#split
stringObject.split(separator,howmany)
var string = "2020.01.10";
string.split(".") // ["2020", "01", "10"]
var string = "html,css,javascript";
string.split(/,/, 2) // ["html", "css"]
string.split(/(,)/) // ["html", ",", "css", ",", "javascript"]
String#match
stringObject.match(regexp)
依赖regexp是否有标志g
如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。
var str="1 plus 2 equal 3"
str.match(/,/) // null
str.match(/\d+/) // ["1", index: 0, input: "1 plus 2 equal 3", groups: undefined]
str.match(/(\d+)/) // ["1", "1", index: 0, input: "1 plus 2 equal 3", groups: undefined]
var str = '1a1 2b c3 4e3'
var reg = /(\d(\w)\d)/
str.match(reg) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。
var str="1 plus 2 equal 3"
str.match(/,/g) // null
str.match(/\d+/g) // ["1", "2", "3"]
str.match(/(\d+)/g) // ["1", "2", "3"]
String#replace
stringObject.replace(regexp/substr,replacement)
// replacement 可以是字符串,也可以是函数。
replacement 中的 $ 字符具有特定的含义。如下表所示,它说明从模式匹配得到的字符串将用于替换。
字符 | 替换文本 |
---|---|
$1、$2、...、$99 | 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。 |
$& | 与 regexp 相匹配的子串。 |
$` | 位于匹配子串左侧的文本。 |
$' | 位于匹配子串右侧的文本。 |
? | 直接量符号。 |
replacement为函数时,如下用法
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2015-01-02'.replace(re, (
matched, // 整个匹配结果 2015-01-02
capture1, // 第一个组匹配 2015
capture2, // 第二个组匹配 01
capture3, // 第三个组匹配 02
position, // 匹配开始的位置 0
S, // 原字符串 2015-01-02
groups // 具名组构成的一个对象 {year, month, day}
) => {
let {day, month, year} = groups;
return `${day}/${month}/${year}`;
});
返回的值,整个替换matched
function converse(str) {
str = str.replace(/([A-Za-z])/g, function(matched, capture1,position,str,groups){
if(capture1>='A'&&capture1<='Z') return capture1.toLowerCase()
else return capture1.toUpperCase()
})
return str
}
console.log(converse('aBc'))
注意:如果 regexp 具有全局标志 g,那么 replace() 方法将替换所有匹配的子串。否则,它只替换第一个匹配子串。
var string = "2020.01.10";
string.replace(".", "/") // "2020/01.10"
string.replace(/\./, "/") // "2020/01.10"
string.replace(/\./g, "/") // "2020/01/10"
string.replace(/(10)/g, "$1 00:00:00") // "2020.01.10 00:00:00"
string.replace(/(10)/g, "$` 00:00:00") // "2020.01.2020.01. 00:00:00"
string.replace(/(10)/g, "$' 00:00:00") // "2020.01. 00:00:00"
string.replace(/(10)/g, "$& 00:00:00") // "2020.01.10 00:00:00"
string.replace(/(10)/g, "? 00:00:00") // "2020.01.$ 00:00:00"
RegExp#test
test() 方法用于检测一个字符串是否匹配某个模式
RegExpObject.test(string)
var string = '123456'
/\d/.test(string) //true
RegExp#exec
如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看得出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。
有g
var string ='123'
var patt = /\d/g
patt.exec(string) // ["1", index: 0, input: "123", groups: undefined]
patt.exec(string) // ["2", index: 1, input: "123", groups: undefined]
patt.exec(string) // ["3", index: 2, input: "123", groups: undefined]
patt.exec(string) // null
patt.exec(string) // ["1", index: 0, input: "123", groups: undefined]
没有g
var string ='123'
var patt = /\d/
patt.exec(string) // ["1", index: 0, input: "123", groups: undefined]
patt.exec(string) // ["1", index: 0, input: "123", groups: undefined]
有g
var str = '1a1 2b c3 4e3'
var reg = /(\d(\w)\d)/g
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
reg.exec(str) // ["4e3", "4e3", "e", index: 10, input: "1a1 2b c3 4e3", groups: undefined]
reg.exec(str) // null
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
没有g
var str = '1a1 2b c3 4e3'
var reg = /(\d(\w)\d)/
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
reg.exec(str) // ["1a1", "1a1", "a", index: 0, input: "1a1 2b c3 4e3", groups: undefined]
RegExp的静态属性
字符 | 替换文本 |
---|---|
$1、$2、...、$99 | 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。 |
RegExp.input / RegExp["$_"] | 最近一次目标字符串 |
RegExp.lastMatch / RegExp["$&"] | 最近一次匹配的文本 |
RegExp.lastParen / RegExp["$+"] | 最近一次捕获的文本 |
RegExp.leftContext / RegExp["$`"] | 目标字符串中lastMatch之前的文本 |
RegExp.rightContext / RegExp["$'"] | 目标字符串中lastMatch之后的文本 |
RegExp.lastIndex | 下一次匹配开始的位置 |
var regex = /(\d)[a-z]/g;
var string = "11a2b";
string.match(regex); // ["1a", "2b"]
RegExp.input // "11a2b"
RegExp.lastMatch // "2b"
RegExp.lastParen // "2"
RegExp.leftContext // "11a"
RegExp.rightContext // ""