JS 掌握正则表达式
如果你没有经历过失败,就说明你没有努力突破极限,而如果你不努力突破极限,你就不能最大限度的挖掘自己的潜能。
正则表达式,对程序员来说在工作中具有非常重要的地位,主要用来匹配或者替换指定字符串,它的功能非常强大,既简单又复杂,掌握它将会让你在编程中如虎添翼。
内容:
- 创建匹配模式
- test()方法
- 多种匹配模式匹配字符串
- 匹配时忽略大小写
- 提取匹配项match()方法
- 全局匹配
- 用通配符.匹配任何内容
- 多种可能性匹配[]
- 连字符(-)匹配字符集
- 连字符-匹配字符串中的字符和数字
- 匹配非指定字符
- 匹配出现1次或1次以上的字符
- 匹配出现0次或1次以上的字符
- 使用惰性匹配来查找字符
- 匹配字符串的开头
- $匹配字符串的结尾
- \w匹配所有单个字母和数字
- \W匹配除了字母和数字的所有单个符号
- \d匹配所有数字
- \D匹配所有非数字
- 匹配空白字符
- 匹配非空白字符
- 指定匹配的上限和下限{}
- 指定可选的元素(? 0或1个)
- 正向先行断言和负向先行断言
- 使用捕获组重复使用
- replace(regex,str) 字符串正则替换
- 删除字符串的开头和结尾的空格
创建匹配模式/Regex/
先来简单认识下它吧,如果你想在"Hello, World!"
字符串中匹配到"Hello",这个单词,那么如何创建这个正则表达式呢?只需要/Hello/
,用两根筷子夹在它身边就ok了!
test()
方法
创建好正则/Hello/
后,使用test(),它会把匹配模式应用到你的内容,如匹配到则返回true
,否则返回false
。请看下面例子:
tips:默认区分大小写
let myString = "Hello, World!";
let myRegex = /Hello/;
let result = myRegex.test(myString); // 返回true
多种匹配模式匹配字符串
多种匹配模式使用|
来分隔多种匹配模式,表示或者
的意思,例如:你想匹配yes
或者no
,你的正则表达式是这么写:/yes|no/
。
下面这个例子,只要petRegex
这个正则表达式匹配到petString
中包含有dog或cat或bird或fish
,result都等于true。
let petString = "James has a pet cat.";
let petRegex = /dog|cat|bird|fish/;
let result = petRegex.test(petString);
匹配时忽略大小写
正则表达式对于英文字母的匹配模式默认是大小写敏感的,但是如何才能去掉这个限制呢?就是不区分大小写呢?很简单在正则后背添加i
即可。
如/ignorecase/i
,可以匹配"ignorecase"
、"igNoreCase"
和"IgnoreCase"
等字符串。
提取匹配项match()
方法
字符串的match()方法,接收一个正则匹配模式为参数,把匹配到的内容提取出来并返回一个新数组。
"Hello, World!".match(/Hello/);
// Returns ["Hello"]
let ourStr = "Regular expressions";
let ourRegex = /expressions/;
ourStr.match(ourRegex);
// Returns ["expressions"]
全局匹配
到目前为止,你只能执行一次匹配模式或一次提取数据而已,但如何提取或匹配所有相关的内容呢?请看下面的答案:
g
表示该正则表达式是全局匹配或称多次匹配,可与i
配合使用,gi
表示全局匹配和不区分大小写匹配。
let repeatRegex = /Repeat/g;
testStr.match(repeatRegex);
// Returns ["Repeat", "Repeat", "Repeat"]
let twinkleStar = "Twinkle, twinkle, little star";
let starRegex = /Twinkle/gi;
let result = twinkleStar.match(starRegex);
//Returns [Twinkle, twinkle]
用通配符.
匹配任何内容
前面的讲解都是精确匹配,而
/./
是匹配所有。
通配符的匹配模式我更认为是叫模糊匹配符,有时候你想匹配某个单词,但你只清楚它的其中几个字母的构造,这时候你就可以使用通配符来占位你不确定的字母,这样它就可以帮你把相关的单词给匹配出来。
例如,如果你想匹配"hug"
、"huh"
、"hut"
和"hum"
,你可以使用正则表达式/hu./
匹配以上四个单词
let humStr = "I'll hum a song";
let hugStr = "Bear hug";
let huRegex = /hu./;
humStr.match(huRegex); // Returns ["hum"]
hugStr.match(huRegex); // Returns ["hug"]
多种可能性匹配[]
[]
,填入1个或1个以上字符就可以创建多种可能的匹配模式,例如,你想要匹配"bag"
、"big"
和"bug"
,但是不想匹配"bog"
。你可以创建正则表达式/b[aiu]g/来执行此操作,[aiu]
只匹配字符"a"
、"i"
或者"u"
的字符。
let bigStr = "big";
let bagStr = "bag";
let bugStr = "bug";
let bogStr = "bog";
let bgRegex = /b[aiu]g/;
bigStr.match(bgRegex); // Returns ["big"]
bagStr.match(bgRegex); // Returns ["bag"]
bugStr.match(bgRegex); // Returns ["bug"]
bogStr.match(bgRegex); // Returns null
连字符(-)
匹配字符集
假如你想匹配字符集里某个范围内的任意字符,那么你可以使用连字符-
来进行连接,表示字符和另一个字符之间的集合。
例如,要匹配小写字母a
到e
,你可以使用[a-e]
,[a-z]
则匹配所有小写字符。
let catStr = "cat";
let batStr = "bat";
let matStr = "mat";
let bgRegex = /[a-e]at/;
catStr.match(bgRegex); // Returns ["cat"]
batStr.match(bgRegex); // Returns ["bat"]
matStr.match(bgRegex); // Returns null
连字符-
匹配字符串中的字符和数字
连字符不仅可以应用于字符,还可以应用于数字。比如,[0-5]
,则匹配0
和5
之间的任意数字。所以你还可以跟一系列字符和数字组合起来使用。
let jennyStr = "Jenny8675309";
let myRegex = /[a-z0-9]/ig;
//myRegex表示匹配jennyStr中所有的字母和数字
jennyStr.match(myRegex);
匹配非指定字符
在你不想匹配的字符前插入^
这个符号,即可创建排除字符集的表达式。
例如,/[^aeiou]/gi匹配所有非元音字符。注意,字符.、!、[、@、/和空白字符等也会被匹配,该否定字符集仅排除元音字符。
下面创建了一个匹配所有非数字或元音字符的正则表达式。
let quoteSample = "3 blind mice.";
let myRegex = /[^0-9aeiou]/ig;
let result = quoteSample.match(myRegex); // 返回[,b,l,n,d, ,m,c,.]
+
匹配出现1次或1次以上的字符
有时,你需要匹配出现1次或连续出现多次的字符(或字符组),这时候你可以使用符号+
。
例如,/a+/g
会在"abc"
中匹配到一个匹配项,并且返回["a"]
。因为+
的存在,它也会在"aabc"
中匹配到一个匹配项,然后返回["aa"]
。
let difficultSpelling = "Mississippi";
let myRegex = /s+/g;
let result = difficultSpelling.match(myRegex);
console.log(result)//返回["ss","ss"]
*
匹配出现0次或1次以上的字符
+是匹配1次或1次以上,表示的是匹配0次或1次以上的字符,如下,正则/go/,表示匹配"g"
及其后面出现0
次或多次
以上的"o"
。
let soccerWord = "gooooooooal!";
let gPhrase = "gut feeling";
let oPhrase = "over the moon";
let goRegex = /go*/;
soccerWord.match(goRegex); // Returns ["goooooooo"]
gPhrase.match(goRegex); // Returns ["g"]
oPhrase.match(goRegex); // Returns null
?
使用惰性匹配来查找字符
正则表达式的默认匹配模式是贪婪匹配(尽可能的多的匹配),惰性匹配呢?(意思是尽可能少的匹配)。
例如:你可以将正则表达式/t[a-z]*i/
应用于字符串"titanic"
。这个正则表达式是一个以t
开始,以i
结束,并且中间有一些字母的匹配模式。
贪婪匹配最后返回["titani"]
,它会尽可能多的匹配。
假如你想使用尽可能少的匹配(惰性匹配)
,可以使用?
,如:/t[a-z]*?i/
,所以[a-z]
区间的字母会被尽可能的忽略,所以最后则给你返回["ti"]
。
let text = "titanic";
let myRegex1 = /t[a-z]*i/; //默认贪婪匹配
let myRegex2 = /t[a-z]*?i/; //惰性匹配
let result1 = text.match(myRegex1); //["titani"]
let result2 = text.match(myRegex2);//["ti"]
匹配字符串的开头
^
符号放在字符集中表示否定,但是把^
放在字符的外面的最头部,表示匹配字符串的开头,例如:
let firstString = "Ricky is first and can be found.";
let firstRegex = /^Ricky/;
firstRegex.test(firstString);
// Returns true
let notFirst = "You can't find Ricky now.";
firstRegex.test(notFirst);
// Returns false
$
匹配字符串的结尾
^
以字符串开头作为匹配模式,$
是以字符串的结尾作为匹配模式。例如:/story$/
表示字符串的末尾为"story"
才会匹配成功。
let theEnding = "This is a never ending story";
let storyRegex = /story$/;
storyRegex.test(theEnding);
// Returns true
let noEnding = "Sometimes a story will have to end";
storyRegex.test(noEnding);
// Returns false
\w
匹配所有单个字母和数字
\w
是[A-Za-z0-9_]
的缩写,记住,它还会匹配下划线字符(_)
。
let longHand = /[A-Za-z0-9_]+/;
let shortHand = /\w+/;
let numbers = "42";
let varNames = "important_var";
longHand.test(numbers); // Returns true
shortHand.test(numbers); // Returns true
longHand.test(varNames); // Returns true
shortHand.test(varNames); // Returns true
下面是统计quoteSample
中字母和数字字符的数量
let quoteSample = "The five boxing wizards jump quickly.";
let alphabetRegexV2 = /\w/g;
let result = quoteSample.match(alphabetRegexV2).length;
//result 等于31
\W
匹配除了字母和数字的所有单个符号
\w
匹配所有单个的字母和数字符号,\W
则正好相反,是[^A-Za-z0-9_]
的缩写,通常相反的匹配模式用大写字母
来表示。
let shortHand = /\W/;
let numbers = "42%";
let sentence = "Coding!";
numbers.match(shortHand); // Returns ["%"]
sentence.match(shortHand); // Returns ["!"]
\d
匹配所有数字
\d
等同于[0-9]
,匹配0
到9
之间任意数字的单个字符。
let string = "Catch 2";
let numRegex = /\d/;
let result = string.match(numRegex);
//result 等于["2"]
\D
匹配所有非数字
小写\d
是表示查找所有数字,大写\D
正好相反,等同于[^0-9]
,匹配所有非数字。
let numString = "Your sandwich will be $5.00";
let noNumRegex = /\D/g;
let result = numString.match(noNumRegex).length;
//result 等于24
匹配空白字符
\s
可以匹配字符之间的空格,它还匹配回车符
、制表符
、换页符
和换行符
,你可以将其视为与[\r\t\f\n\v]
类似。
let whiteSpace = "Whitespace. Whitespace everywhere!"
let spaceRegex = /\s/g;
whiteSpace.match(spaceRegex);
// Returns [" ", " "]
匹配非空白字符
\s
来搜寻空白字符,\S
则搜寻除了空白字符之外的字符。此匹配模式将不匹配空格
、回车符
、制表符
、换页符
和换行符
。你可以认为这类似于字符类[^\r\t\f\n\v]
。
let whiteSpace = "Whitespace. Whitespace everywhere!"
let nonSpaceRegex = /\S/g;
whiteSpace.match(nonSpaceRegex).length; // Returns 32
指定匹配的上限和下限{}
{}
可以通过数字设置上限和下限来限定匹配字符的出现个数,例如,要在字符串"ah"
中匹配仅出现3
到5
次的字母a
,你的正则表达式应为/a{3,5}h/
。
-
{n,}
:至少匹配n
个以上,n
是一个非负整数 -
{n}
:精确匹配n
次,如/o{2}/
,匹配2
个o
,n
是一个非负整数 -
{m,n}
: 其中n <= m
,最少匹配n
次且最多匹配m
次
let A4 = "aaaah";
let A2 = "aah";
let multipleA = /a{3,5}h/;
multipleA.test(A4); // Returns true
multipleA.test(A2); // Returns false
指定可选的元素(? 0或1个)
有时候你的匹配模式无法确定存在的部分,那么你可以使用?
来表示0
个或1
个,你可以将此符号视为前面的元素是可选的。
例如,美式英语和英式英语略有不同,你可以使用问号来匹配两种拼写
let american = "color";
let british = "colour";
let rainbowRegex= /colou?r/;
rainbowRegex.test(american); // Returns true
rainbowRegex.test(british); // Returns true
正向先行断言和负向先行断言
先行断言
可以在同一个字符串上搜寻多个匹配模式。有两种先行断言
:正向先行断言
和负向先行断言
:
正向先行断言
会查看并确保搜索匹配模式中的元素存在,但实际上并不匹配。正向先行断言的用法是(?=...)
,其中...
就是需要存在但不会被匹配的部分,将返回匹配模式的其余部分。
负向先行断言
会查看并确保搜索匹配模式中的元素不存在。负向先行断言
的用法是(?!...)
,其中...
是你希望不存在的匹配模式。如果负向先行断言
部分不存在,将返回匹配模式的其余部分。
实例:
let quit = "qu";
let noquit = "qt";
let quRegex= /q(?=u)/;
let qRegex = /q(?!u)/;
quit.match(quRegex); // Returns ["q"]
noquit.match(qRegex); // Returns ["q"]
一个简单的密码检查器,密码规则是 3 到 6 个字符且至少包含一个数字:
let password = "abc123";
let checkPass = /(?=\w{3,6})(?=\D*\d)/;
checkPass.test(password); // Returns true
使用捕获组重复使用
有时候需要使用到多次重复的匹配模式,重复编写表达式是非常繁琐的,这时候就可以使用捕获组来解决这个问题。
捕获组
搜寻重复的子字符串。括号(
和)
可以用来匹配重复的子字符串。你只需要把重复匹配模式的正则表达式放在括号中即可。
要指定重复字符串将出现的位置,可以使用反斜杠(\)
后接一个数字。这个数字从 1
开始,随着你使用的每个捕获组的增加而增加。这里有一个示例,\1
可以匹配第一个组。
let repeatStr = "regex regex";
let repeatRegex = /(\w+)\s\1/;
repeatRegex.test(repeatStr); // Returns true
repeatStr.match(repeatRegex); // Returns ["regex regex", "regex"]
["regex regex", "regex"]
,该数组index
为1
的元素是捕获组匹配到的元素。
let testString = "test test test test test test";
let reRegex =/(test)(\s)\1\2\1/g; //这里的2表示(\s)
let result = reRegex.test(testString);
replace(regex,str)
字符串正则替换
字符串
上.replace()
方法来搜索并替换字符串中的文本。.replace()
的第1个参数为正则表达式匹配模式,第2个参数是用于替换匹配的字符串或用于执行某些操作的函数。
let wrongText = "The sky is silver.";
let silverRegex = /silver/;
let result = wrongText.replace(silverRegex, "blue");
// Returns "The sky is blue."
你还可以使用美元符号($)访问替换字符串中的捕获组。
"Code Camp".replace(/(\w+)\s(\w+)/, '$2 $1'); //本身替换本身
// Returns "Camp Code"
删除字符串的开头和结尾的空格
let hello = " Hello, World! ";
let wsRegex = /^\s+|\s+$/g; // 修改这一行
let result = hello.replace(wsRegex,''); // 修改这一行
//Returns "Hello, World!"
注:.trim()方法在这里也可以实现同样的效果