JavaScript - 正则表达式

RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。

函数实际上是 Function 类型的实例,因此函数也是对象;而这一点整是 JavaScript 最有特色的地方。由于函数对象,所以函数也拥有方法,可以用来争抢其行为。

因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当做对象来访问,三种基本包装类型分别是:Boolean、Number和String。

  • 每个包装类型都映射到同名的基本类型。
  • 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作。
  • 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。

在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和 Math 。在大多数 ECMAScript 实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变量和函数都是 Global 对象的属性。Math 对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。

创建正则表达式

var expression = / pattern / flags ;
var expression1 = new RegExp('pattern', flags);

使用类似Perl的语法,可以创建一个正则表达式。

其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、向前查找以及反向引用。

  • g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;
  • i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
  • m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在于模式匹配的项;

与其他语言中的正则表达式类似,模式中使用的所有元字符都必须转义。

/*
  正则表达式包括:

  ( [ { / ^ $ | ? * + . } ] )

  这些元字符在正则表达式中都有一或多种特殊用途,因此如果想要匹配字符串中包含的这些字符,就必须对它们进行转义
*/


// 匹配字符串中所有 'at' 的实例
var pattern1 = /at/g;


// 匹配第一个'bat' 或 'cat', 不区分大小写
var pattern2 = /[bc]at/i;

// 匹配第一个'[bc]at', 不区分大小写
var pattern2 = /\[bc\]at/i;


// 匹配所有以 ' at' 结果的3个字符的组合,不区分大小写
var pattern3 = /. at/gi;

// 匹配所有以 '.at',不区分大小写
var pattern3 = /\. at/gi;
字面量模式 等价的字符串
/[bc]at/ "\\[bc\\]at"
/.at/ "\\.at"
/name/age/ "name\\/age"
/\d.\d{1, 2}/ "\\d.\\d{1, 2}"
/\w\hello\123/ "\\w\\\\hello\\\\123"

字符串 \ 在字符串中通常被转义为 \\, 而在正则表达式字符串中就会变成 \\\\

var re = null, i;

for (i=0; i > 10; i++) {
  re = /cat/g;
  re.test("catastrophe");
}

for (i=0; i > 10; i++) {
  re = new RegExp("cat", "g");
  re.test("catastrophe");
}

test() 方法用来匹配传入的字符串是否符合正则表达式。

ECMAscript 5 之前 使用字面量不是创建一个新的正则表达式实例,有点像单例模式,会导致循环调用test时失败的情况。

ECMAScript 5 明确规定,使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次都创建新的RegExp示例。IE9、Fiefox 4+、和Chrome都据此做出了修改。

RegExp 实例属性

RegExp 对象的主要方法是 exec(), 该方法是专门为捕获组而设计的。 exec() 接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回 null。

返回的数组虽然是Array的实例,但包含两个额外的属性:index 和 input。

其中 index 表示匹配项在字符串中的位置,而 input 表示应用正则表达式的字符串。

在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。

Exec

var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;

var matches = pattern.exec(text);
alert(matches.index); // 0
alert(matches.input); // mom and dad and baby

alert(matches[0]); // mom and dad and baby
alert(matches[1]); // and dad and baby
alert(matches[2]); //  and baby

这个实例中包含两个捕获组 ()

最内部的捕获组匹配 "and baby",而包含它的捕获组匹配 "ant dad" 或者 "and dad and baby"。

当把字符串传入 exec() 方法中之后,发现了一个匹配项。

因为整个字符串本身与模式匹配,所以返回的数组 matchs 的 index 属性值为 0。

数组中的第一项是匹配的整个字符串,第二项包含与第一个捕获组匹配的内容,第三项包含与第二个捕获组匹配的内容。

对于 exec() 方法而言,即使在模式中设置了全局标志(g),它每次也只会返回一个匹配项。

在不设置全局标志的情况下,在同一个字符串上多次调用 exec() 将始终返回第一个匹配项的信息。

而在设置全局标志的情况下,每次调用 exec() 则都会在字符串中继续查找新的匹配项。

var text = "cat, bat, sat, fat";
var pattern1 = /.at/;

var matches = pattern1.exec(text);
alert(matches.index); // 0
alert(matches[0]); // cat
alert(pattern1.lastIndex); // 0

matches = pattern1.exec(text);
alert(matches.index); // 0
alert(matches[0]); // cat
alert(pattern1.lastIndex); // 0

上面例子中 pattern1 不是全局模式,因此每次调用 exec() 返回的都是第一个匹配项 ("cat")

var pattern2 = /.at/g;

var matches = pattern2.exec(text);
alert(matches.index); // 0
alert(matches[0]); // cat
alert(pattern2.lastIndex); // 3

matches = pattern2.exec(text);
alert(matches.index); // 5
alert(matches[0]); // bat
alert(pattern2.lastIndex); // 8

上面例子中 pattern2 是全局模式,因此每次调用 exec() 都会返回字符串中的下一个匹配项,直至搜索到字符串末尾为止。

注意 lastIndex 的变化,在全局匹配模式下,lastIndex的值在每次调用 exec() 后都会增加,而在非全局模式下则始终保持不变。

test

接受一个字符串参数,在模式与该参数匹配的情况下返回 true,否则返回 false

在指向知道目标字符串与某个模式是否匹配,但不需要指定其文本内容的情况下,使用这个方法非常方便。

因此,test() 方法经常被用在id语句中。

var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;

if (pattern.test(text)) {
    alert("匹配成功")
}

RegExp 构造函数属性

RegExp 构造函数包含一些属性(这些属性在其他语言中被看成是静态属性)。

这些属性适用于作用域中的所有正则表达式,并且基于所有执行的最近一次正则表达式操作而变化。

关于这些属性的另一个独特之处,就是可以通过连各种方式访问它们。

这些属性分别有一个长属性名和一个短属性名(Opera是例外,它不支持短属性名)。

长属性名 短属性名 说明
input $_ 最近一次要匹配的字符串(Opera未实现)
lastMatch $& 最近一次的匹配项(Opera未实现)
lastParen $+ 最近一次的匹配的捕获组(Opera未实现)
lastContext $ input 字符串中 lastMatch 之前的文本
multiline $* 布尔值,表示是否所有表达式都使用多行模式。(IE和Opera未实现)
rightContext $' Input 字符串中 lastMatch 之后的文本

使用这些属性可以从 exec()test() 执行的操作中提取出更具体的信息。

var text = "this has been a short summer";
var pattern = /(.)hort/g;

if (pattern.test(text)) {
    alert(RegExp.input); // this has been a short summer
    alert(RegExp.leftContext); // this has been a
    alert(RegExp.rightContext); //  summer
    alert(RegExp.lastMatch); // short
    alert(RegExp.lastParen); // s
    alert(RegExp.multiline); // undefined
}
var text = "this has been a short summer";
var pattern = /(.)hort/g;

if (pattern.test(text)) {
    alert(RegExp['$_']); // this has been a short summer
    alert(RegExp["$`"]); // this has been a
    alert(RegExp["$'"]); //  summer
    alert(RegExp['$&']); // short
    alert(RegExp['$+']); // s
    alert(RegExp['$*']); // undefined
}
  • input 属性返回了原始字符串。
  • leftContext 属性返回了单词 short 之前的字符串。
  • rightContext 属性返回了单词 short 之后的字符串。
  • lastMatch 属性返回最近一次与整个正则表达式匹配的字符串。
  • lastParen 属性返回最近一次匹配的捕获数组,即例子中的 s

模式的局限

  • 不匹配字符串开始和结尾的 \A 和 \Z 锚

    但支持以插入符号 (^) 和美元符号 ($) 来匹配字符串的开始和结尾。

  • 不支持向后查找(lookbehind)

    但完全支持向前查找(lookahead)。

  • 不支持原子组(atomic grouping)

  • 不支持Unicode(单个字符除外,如 \uFFFF)

  • 不支持命名的捕获组

    但支持编号的捕获组

  • 不支持 s(single, 单行)x(free-spacing,无间隔) 匹配模式

  • 不支持条件匹配

  • 不支持正则表达式注释

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

推荐阅读更多精彩内容