JavaScript 正则表达式(实例)

RegExp对象

字面量

var reg=/\bis\b/g;定义变量reg然后把正则表达式文本写到两个反斜杠之间,"\正则文本\"\b代表单词边界,\bis\b代表正则is单纯后面再加个\b是保证is是一个完整的单词,而不是两个字符。

var reg=/\bis\b/;
"He is a boy .This is a dog.Where is she?".replace(reg,'IS');
//"He IS a boy .This is a dog.Where is she?"

发现就匹配了第一个单纯is
我们使用g,也就是代表全文搜索匹配。var reg=/\bis\b/g;

var reg=/\bis\b/g;
"He is a boy .This is a dog.Where is she?".replace(reg,'IS');
//"He IS a boy .This IS a dog.Where IS she?"

构造函数

var reg=new RegExp("\\bis\\b","g");使用new操作符来调用构造函数,构造函数接收两个参数,第一个字符串里面是正则表达式的文本,这里有些特殊的地方就是反斜线写了两次,是因为Javascript中反斜线本身就是特殊字符,如果我们想使用的话,就要进行转义,然后第二个参数是字符串,也是标志g也就是代表全文搜索匹配

var reg=new RegExp("\\bis\\b","g");
"He is a boy .This is a dog.Where is she?".replace(reg,'IS');
//"He IS a boy .This IS a dog.Where IS she?"

修饰符

g:global全文搜索,不添加,搜索到第一个匹配停止

"He is a boy .This is a dog.Where is she?".replace(/\bis\b/g,'IS')
"He IS a boy .This IS a dog.Where IS she?"

i:ignore case 忽略大小写,默认大小写敏感

"He Is a boy .This is a dog.Where is she?".replace(/\bis\b/gi,'hello')
"He hello a boy .This hello a dog.Where hello she?"

m:multiple lines 多行搜索

var mulSrt = "@123\n@321\n@876"
mulSrt
"@123
@321
@876 "
mulSrt.replace(/@\d/g, "G")
"G23
G21
G76 "
mulSrt.replace(/^@\d/g, "G")
"G23
@321
@876 "
mulSrt.replace(/^@\d/gm, "G")
"G23
G21
G76 "

元字符

正则表达式由两种基本字符类型组成:

原义文本字符

原义文本字符意思就是代表它本来含义的字符比如/a/就是想匹配a

"jj abc a b c vf".replace(/a/gi,'hello')
//"jj hellobc hello b c vf"

/abc/就是想匹配abc

"jj abc a b c vf".replace(/abc/gi,'hello')
//"jj hello a b c vf"

这些都是原义文本字符。

元字符

元字符实在正则表达式中有特殊含义的非字母字符

比如\b它匹配的是单词边界,他的意思并不是匹配一个反斜线一个字母b,意思是匹配一个单词边界。这种就是特殊字符。

在正则表达式中有几个字符需要注意他们都是有特殊含义的。

Paste_Image.png

字符类

我们工作时希望并不是匹配某个字符,而是希望匹配符合一系列特征abc

我们可以使用元字符[]来构建一个简单的类。
类就是符合某些特征的对象,是指一个泛指,而不是特指某个字符。
比如我们使用表达式[abc]就把a或者b或者c自定义成为一类,表达式就可以匹配这类的字符。他的意思是有它们一个就行。

"a1b2c3".replace(/[abc]/g,'x')
//"x1x2x3"

这样我们发现abc对应的地方都进行替换了,

字符来取反

使用元字符^创建反向类/负向类
反向类的意思是不属于某类的内容
表达式[^abc]表示不是字符a或b或c的内容

"a1b2c3".replace(/[^abc]/g,'x')
//"axbxcx"

把字符a或b或c以为外的字符替换成x了

范围类

正则表达式提供了范围类

我们可以使用[a-z]来链接两个字符表示从a到z的任意字符
这是一个闭区间,也就是包含a和z本身

"a1b2c3x4z9".replace(/[a-z]/g,'Q');
//"Q1Q2Q3Q4Q9"

会发现a-z字母都被替换

[]组成的类内部是可以连写的[a-zA-Z]

"a1b2c3x4z9ASDFGGG".replace(/[a-zA-Z]/g,'Q');
"Q1Q2Q3Q4Q9QQQQQQQ"

匹配所有数字

"2016-11-12".replace(/[0-9]/g,'Q');
"QQQQ-QQ-QQ"

匹配所有数字和横线

"2016-11-12".replace(/[0-9-]/g,'Q');
"QQQQQQQQQQ"

JS预定义类及边界

正则表达式预定义类:

字符 含义
. 除了回车符和换行符之外的所有字符,等价于[^\r\n]
\d 数字字符,等价于[0-9] digit
\D 非数字字符,等价于[^0-9]
\s 空白符,等价于[\t\n\x0B\f\r] space
\S 非空白符,等价于[^\t\b\x0B\f\r]
\w 单词字符(字母,数字,下划线),等价于[a-zA-Z_0-9] word
\W 非单词字符,等价于[^a-zA-Z_0-9]

例子:

匹配一个ab+数字+任意字符的字符串

/ab[0-9][^\r\n]/
"ab12334455sss".replace(/ab[0-9][^\r\n]/g,'Q');
//"Q334455sss"

或者

/ab\d.

"ab3klll".replace(/ab\d./g,"z")
//"zlll"

边界

字符 含义
^ 以xxx开始
$ 以xxx结束
\b 单词边界
\B 非单词边界

\b单词边界

匹配字符

"This is a boy".replace(/is/g,'0')
//"Th0 0 a boy"

会发现所以 is都被替换

如果想替换单词,单词前后是有单词边界,所以要写上边界"This is a boy".replace(/\bis\b/g,'0')

"This is a boy".replace(/\bis\b/g,'0')
//"This 0 a boy"

\B非单词边界

如果想替换Thisis,观察下特征,发现前面并不是边界,后面是边界那就这样写"This is a boy".replace(/\Bis\b/g,'0')

"This is a boy".replace(/\Bis\b/g,'0')
//"Th0 is a boy"

^以xxx为开始

"@123@abc@".replace(/@./g,'Q');
//"Q23Qbc@"

匹配全局@和任意字符

"@123@abc@".replace(/^@./g,'Q');
//"Q23@abc@"

以@和任意字符作为开始后面的不匹配

$以xxx为结束

"@123@abc@".replace(/.@/g,'Q');
//"@12QabQ"

匹配全局任意字符和@

"@123@abc@".replace(/.@$/g,'Q');
//"@123@abQ"

匹配最后一个任意字符和@

var mulSrt = "@123\n@321\n@876"
mulSrt
"@123
@321
@876 "
mulSrt.replace(/@\d/g, "G")
"G23
G21
G76 "
mulSrt.replace(/^@\d/g, "G")
"G23
@321
@876 "
mulSrt.replace(/^@\d/gm, "G")
"G23
G21
G76 "

量词

字符 含义
出现零次或一次(最多出现一次)
+ 出现一次或多次(至少出现一次)
* 出现零次或多次(任意次)
{n} 出现n次
{n,m} 出现n到m次
{n,} 至少出现n次

我们希望匹配一个连续出现20次数字的字符串

/\d\d\d\d\d\d\d\d..../反斜杠加d表示数字表示数字出现20次把他写20遍这样非常麻烦如果出现100次那就要写100遍吗。为了解决这个问题正则表达式引入了量词的概念。

"12341111133333333111111111111".replace(/\d{20}/g,"d")
//"d111111111"

匹配数字两次

"1234".replace(/\d{2}/g,"d")
//"dd"

JS正则贪婪模式与非贪婪模式

贪婪模式

了解了量词我们看这样一个场景。

/\d{3,6}/

数字匹配3到6次,我们用12345678来执行,我们写的正则表达式是匹配数字3到6次,这个字符串中,即可以满足3次4次5次6次,都是可以满足的,那么正则表达式这时候该怎么处理?

正则表达式在处理的时候会尽可能多的匹配,直到匹配失败。

"12345678".replace(/\d{3,6}/g,'A')
//"A78"

我们看到,他是匹配123456,78没有匹配到,也就是说他是尽可能多的匹配而不是少的匹配。

这就是贪婪模式

非贪婪模式

让正则表达式尽可能少的匹配,也就是说一旦匹配成功匹配不再继续尝试,就是非贪婪模式。

做法很简单,在量词后面加上?即可。

"12345678".replace(/\d{3,6}?/g,'A')
"AA78"

这个时候的执行结果就是123,456后面两个78没有被匹配到。

分组

匹配字符串Byron连续出现3次的场景。

没有接触量词的时候我们把这个单词写3遍,接触量词之后我们可能会这样写Byron{3}但是它代表的含义和我们预期的并不是一致的。实际上是n重复3次,前面不重复,量词是作为紧挨着它的字符,并不是整个单词,否则怎么知道你匹配到哪。

"ByronByronByron".replace(/Byron{3}/g,'A')
//"ByronByronByron"
"ByronnnByronByron".replace(/Byron{3}/g,'A')
//"AByronByron"

那么如何让他匹配整个单词呢?或者是我们圈定的内容,那么就用到分组

使用()可以达到分组功能,使量词作用于分组。

(Byron){3}这样写就能达到我们预期效果。整个单词重复了3遍。

比如想匹配一个小写字母加一个数字连续出现3次a1b2c3d4

`a1b2c3d4`.replace(/[a-z]\d{3}/g,"A")
//"a1b2c3d4"

这样写是匹配不到的,因为\d{3}是找数字出现3次的场景。

我们将他分组即可

`a1b2c3d4`.replace(/([a-z]\d){3}/g,"A")
//"Ad4"

这样就达到效果了。这样量词作用于整个分组。

使用|可以达到或的效果

"ByronCasper".replace(/Byron|Casper/g,"A");
//"AA"

这样两个都被匹配到了。

分组在或中的使用

"ByronsperByrCasper".replace(/Byr(on|Ca)sper/g,"A");
//"AA"

反向引用

比如我们想把2016-11-25变成11/25/2016

如果只是想把-替换成/是很简单的

"2016-11-25".replace(/-/g,'/')
//"2016/11/25"

但是它顺序也变了,

以往的写法

"2016-11-25".replace(/\d{4}-\d{2}-\d{2}/g,'11/25/2016')
//"11/25/2016"

但是需要匹配的值变成了2016,月份可能变成11,我们想替换他本身,替换的内容不再是一个常量,而是一个变量。这个时候该怎么处理?

我们用反向引用,

"2016-11-25".replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$3')
"11/25/25"

我们用$引用分组内内容,我们对分组内容进行捕获,捕获后用$1$2$3来代替。

"2016-11-25".replace(/(\d{4})-(\d{2})-(\d{2})/g,'$1')
//"2016"
 "2016-11-25".replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2')
//"11"
 "2016-11-25".replace(/(\d{4})-(\d{2})-(\d{2})/g,'$3')
//"25"

"2016-11-25".replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$3')
"11/25/25"

忽略分组

不希望捕获某些分组,只需要在分组内加上?:就可以。

"abcaok".replace(/(abc).(ok)/g,'$1/$2')
//"abc/ok"

"abcaok".replace(/(?:abc).(ok)/g,'$1/$2')
//"ok/$2"

前瞻

正则表达式的前瞻:

  1. 正则表达式从文本头部向尾部开始解析,文本尾部方向,成为“前”
  2. 前瞻 就是在正则表达式匹配到规则的时候,向前检查是否符合断言。比如找到儿子为张三,还得看看他的父亲是否是李四
    后顾/后瞻方向相反

注意:JavaScript不支持后顾

匹配单词数字加数字

"a2*3".replace(/\w(\d)/g,"A");
//"A*3"

匹配单词数字,注:这个单词数字后面必须有数字才会匹配,(?=\d)不能算在匹配内容,这是断言。

"a2*3".replace(/\w(?=\d)/g,"A");
//"A2*3"

写个复杂点的案例

"a2*34v8".replace(/\w(?=\d)/g,"A");
//"A2*A4A8"

a2*34``v8这三个符合要求

"a2*34vv".replace(/\w(?=\d)/g,"A");
//"A2*A4vv"

a2*34vv,这里只有两个匹配vvv是对的但是它后面不是数字,所以不成功。

现在改一下比配后面不是数字的

"a2*34vv".replace(/\w(?!\d)/g,"A");
"aA*3AAA"

a2*``34``vv,2变成A。4vv都符合所以是AAA

js对象属性

描述 默认
g:global是否全文搜索 默认false
i:ignore case是否大小写敏感 默认false
m:multiline多行搜索 默认值false
lastIndex:当前正则表达式匹配内容的最后一个字符的下一个位置(即下一次匹配开始的位置)。
source : 正则表达式的文本字符串。

test 和 exec方法

正则表达式本身的两个方法
1.test
RegExp.prototype.test(str)

用于测试字符串参数中是否存在匹配正则表达式模式的字符串

如果存在则返回true,否则返回false

lastIndex 记录当前匹配结果的、最后一个字符的、下一个字符的位置
注意:test()方法在匹配的时候当匹配到一个结果时,会从lastIndex位置开始匹配下一个结果,直到不存在的时候才置为0。因此,当使用全局g属性标识时,当匹配到最后一个结果时,lastIndex值指向不存在的位置,此时再执行test()会返回false。
例子:多次执行test()方法,会在true、false之间循环
(/\w/g).test('a')每次执行都是正确的,但是通过实例化对象,需要很大的开销
test()方法:原意就是测试有没有、能不能匹配上,当使用test原意时,没必要加g

2.exec

RegExp.prototype.exec(str)
使用正则表达式模式对字符串执行搜索,并将更新全局RegExp对象的属性一反映匹配结果
如果没有匹配的文本则返回 null,否则返回一个结果数组:

  • index 声明匹配文本的第一个字符位置
  • input 存放被检索的字符串 string

非全局调用
调用非全局的RegExp对象的 exec()时,返回数组
第一个元素是与正则表达式相匹配的文本
第二个元素是与RegExpObject的第一个子表达式相匹配的文本(如果有的话)
第三个元素是与RegExp对象的第二个子表达式相匹配的文本(如果有的话),以此类推

字符串对象方法

String.prototype.search(reg)

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。

语法

stringObject.search(regexp)
参数 描述
regexp 该参数可以是需要在 stringObject 中检索的子串,也可以是需要检索的 RegExp 对象。注释:要执行忽略大小写的检索,请追加标志 i。

返回值

stringObject 中第一个与 regexp 相匹配的子串的起始位置。

注释:如果没有找到任何匹配的子串,则返回 -1。

说明

search() 方法不执行全局匹配,它将忽略标志 g。它同时忽略 regexp 的 lastIndex 属性,并且总是从字符串的开始进行检索,这意味着它总是返回 stringObject 的第一个匹配的位置。

"a1b1c1d1".search('1')
//1
"a1b1c1d1".search('10')
//-1
"a1b1c1d1".search(1)
//1
"a1b1c1d1".search(/1/)
//1

String.prototype.match(reg)

match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。

该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。

参数 描述
searchvalue 必需。规定要检索的字符串值。
regexp 必需。规定要匹配的模式的 RegExp 对象。如果该参数不是 RegExp 对象,则需要首先把它传递给 RegExp 构造函数,将其转换为 RegExp 对象。

返回值

存放匹配结果的数组。该数组的内容依赖于 regexp 是否具有全局标志 g。

说明

match() 方法将检索字符串 stringObject,以找到一个或多个与 regexp 匹配的文本。这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g。

如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject
中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回
null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0
个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index
属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。

如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject
中的所有匹配子字符串。若没有找到任何匹配的子串,则返回
null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是
stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。

注意:在全局检索模式下,match() 即不提供与子表达式匹配的文本的信息,也不声明每个匹配子串的位置。如果您需要这些全局检索的信息,可以使用 RegExp.exec()。

var str="Hello world!"
document.write(str.match("world") + "<br />")
document.write(str.match("World") + "<br />")
document.write(str.match("worlld") + "<br />")
document.write(str.match("world!"))

输出

world
null
null
world! 

正则方法非全局匹配

var reg3 = /\d(\w)/;
var reg4 = /\d(\w)/g;
var ts = '$1a2b3c4d5e';

var ret = ts.match(reg3);
console.log(ret);    //["1a", "a", index: 1, input: "$1a2b3c4d5e"]
document.write(ret);  //1a,a

正则方法全局匹配

var reg3 = /\d(\w)/;
var reg4 = /\d(\w)/g;
var ts = '$1a2b3c4d5e';

var ret = ts.match(reg4);
console.log(ret);   //["1a", "2b", "3c", "4d", "5e"]
document.write(ret);//1a,2b,3c,4d,5e

String.prototype.match(reg)方法

split() 方法用于把一个字符串分割成字符串数组。

基本用法

var op = 'a,b,c,d';
var spo = op.split(',');
console.log(spo);
//["a", "b", "c", "d"]

在一些复杂分割情况下可以用正则用法

var op = 'a1b2c3d';
var spo = op.split(/\d/);
console.log(spo);
//["a", "b", "c", "d"]

再复杂

var op = 'a,b|c?d';
var spo = op.split(/[,|\|\?]/g);
console.log(spo);
//["a", "b", "c", "d"]

String.prototype.replace方法

传入两个参数replace(找谁,替换谁)

"a1b".replace(/1/,2)
//"a2b"


"a1b1c1".replace(/1/g,2)
//"a2b2c2"

"a1b1c1".replace(/\d/g,2)
"a2b2c2"

如果我想把"a1b2c3d4" => "a2b3c4d5"该怎么实现呢?

var h = "a1b2c3d4".replace(/\d/g, function(match, index, origin) {
    //console.log(index);
    return parseInt(match) + 1;
});
console.log(h);//a2b3c4d5



var h = "a1b2c3d4e5".replace(/(\d)(\w)(\d)/g, function(match, g1, g2, g3, index, origin) {
    //console.log(index);
    return g1 + g3;
});
console.log(h);//a12c34e5
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容