JavaScript正则表达式语法与RegExp对象详解
本文系统梳理JavaScript中正则表达式的核心语法,涵盖普通字符、特殊字符、转义规则及贪婪与懒惰模式。重点解析RegExp对象的创建方式、实例属性(如global、source)及exec与test方法的行为差异,并通过PhoneGap源码案例深入剖析分组匹配机制,帮助开发者掌握JS正则的高级应用技巧。
需要明确的是,本文仅总结正则表达式中常用且基础的语法,并未涵盖所有复杂规则。从实际应用角度看,掌握这些基础语法已足以应对绝大多数日常开发需求。值得注意的是,正则表达式并非ECMAScript独有,Java、.NET以及Unix系统环境均支持类似机制,本文将以ECMAScript标准为基础进行阐述。
一、正则表达式基础
正则表达式基础语法
1、普通字符:包括字母、数字、下划线、汉字以及所有不具备特殊含义的字符,例如ABC123。在匹配过程中,正则表达式会直接寻找与这些字符完全一致的内容。
2、特殊字符:部分字符具有特定含义,若需匹配其字面意思,必须使用反斜杠“\”进行转义处理。
| 字符 | 含义 | 字符 | 含义 | 字符 | 含义 | 字符 | 含义 |
| \a | 响铃符 = \x07 | ^ | 匹配字符串的开始位置 | \b | 匹配单词的开始或结束 | {n} | 匹配n次 |
| \f | 换页符 = \x0C | $ | 匹配字符串的结束位置 | \B | 匹配不是单词开始和结束的位置 | {n,} | 匹配至少n次 |
| \n | 换行符 = \x0A | () | 标记一个子表达式的开始和结束 | \d | 匹配数字 | {n,m} | 匹配n到m次 |
| \r | 回车符 = \x0D | [] | 自定义字符组合匹配 | \D | 匹配任意不是数字的字符 | [0-9] | 匹配0到9中任意一个数字 |
| \t | 制表符 = \x09 | {} | 修饰匹配次数的符号 | \s | 匹配任意空白字符 | [f-m] | 匹配f到m中任意一个字母 |
| \v | 垂直制表符 = \x0B | . | 匹配除换行符外的字符 | \S | 匹配任意非空白字符 | ||
| \e | ESC符 = \x1B | ? | 匹配0或1次 | \w | 匹配字母或数字或下划线或汉字 | ||
| \xXX | 使用两位十六进制表示形式,可与该编号的字符匹配 | + | 匹配1或多次 | \W | 匹配任意不是字母、数字、下划线和汉字的字符 | ||
| \uXXXX | 用四位十六进制表示形式,可与该编号的字符匹配 | * | 匹配0或多次 | [^x] | 匹配除x外的所有字符 | ||
| \x{XXXXXX} | 使用任意位十六进制表示形式,可与该编号的字符匹配 | | | 左右两边表达式之间“或”关系 | [^aeiou] | 匹配除aeiou外的所有字符 |
上述列举的特殊字符可大致归纳为以下几类:
(1)不可见或不便书写的控制字符:例如响铃符(\a)、换页符(\f)、换行符(\n)、回车符(\r)、制表符(\t)以及ESC符(\e)。
(2)十六进制表示的字符:包括两位十六进制(\x02)、四位十六进制(\x012B)以及任意位数的十六进制表示(\x{A34D1})。
(3)位置锚点字符:用于指定匹配位置,如字符串起始位置(^)、字符串结束位置($)、单词边界开始与结束(\b)以及非单词边界(\B)。
(4)量词字符:用于指定匹配次数,包括0或1次(?)、1次或多次(+)、0次或多次(*)、精确n次({n})、至少n次({n,})以及n到m次之间({n,m})。
(5)修饰符字符:用于定义匹配范围或结构,包括次数修饰({})、自定义字符组合匹配([])以及子表达式分组(())。
(6)反义字符:用于匹配特定条件之外的内容,具体分为以下几种情况:
(A)通过大小写或类型反义:例如\b与\B、\d与\D、\s与\S、\w与\W,分别匹配单词边界与非边界、数字与非数字、空白字符与非空白字符、字母数字下划线汉字与非此类字符。
(B)通过否定字符集反义:例如[^x]匹配除x以外的任意字符,[^aeiou]匹配除元音字母aeiou以外的任意字符。
(C)其他特殊反义情况:例如\n(换行符)与.(点号,匹配除换行符外的任意字符)在特定语境下构成反义关系。
(7)范围字符:用于指定字符区间,如数字范围([0-9])匹配0到9之间的任意数字,字母范围([f-m])匹配f到m之间的任意字母。
(8)逻辑字符:主要用于表示“或”关系,使用符号|连接左右两边的表达式。
3、转义机制:
(1)使用反斜杠“\”对单个特殊字符进行转义,使其失去特殊含义。
(2)使用“\Q...\E”结构进行转义,将\Q与\E之间的所有字符均视为普通字符处理。
(3)使用“\U...\E”结构进行转义,将\U与\E之间的字符视为普通字符,并将其中的小写字母转换为大写进行匹配。
(4)使用“\L...\E”结构进行转义,将\L与\E之间的字符视为普通字符,并将其中的大写字母转换为小写进行匹配。
4、贪婪模式与懒惰模式:
当正则表达式中包含量词字符时,默认情况下引擎会尽可能多地匹配字符,这被称为贪婪模式。例如使用l*n匹配字符串“linjisong”时,会匹配出“linjison”而非最短的“lin”。相反,通过在量词后添加“?”可切换为懒惰模式,即尽可能少地匹配字符。例如*?表示重复0次或多次,但优先选择最少的重复次数。
5、分组和反向引用:
(1)使用小括号(())将表达式包裹,可使该部分作为一个整体进行处理,实现分组目的。
(2)默认情况下,每个分组会自动获得一个组号,编号顺序依据左括号出现的先后,从1开始递增。
(3)引擎在处理时会保存小括号内表达式匹配到的内容,以便在匹配过程中或结束后进一步使用。可通过反斜杠后跟组号来引用该内容,例如\1表示引用第一个分组匹配到的文本。
(4)支持自定义组名,语法为(?<name>exp)。在使用反向引用时,除数字组号外,还可使用\k<name>形式引用命名分组。
(5)若无需保存匹配内容且不需要分配组号,可使用语法(?:exp)定义非捕获分组。
(6)小括号还有其他特殊语法形式,此处列举几种常见用法,不再深入展开。
| 分类 | 代码/语法 | 说明 |
|---|---|---|
| 捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
| (?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) | |
| (?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
| 零宽断言 | (?=exp) | 匹配exp前面的位置 |
| (?<=exp) | 匹配exp后面的位置 | |
| (?!exp) | 匹配后面跟的不是exp的位置 | |
| (?<!exp) | 匹配前面不是exp的位置 | |
| 注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
至此,理解常用正则表达式的基础已足够。若需深入学习,可参考《正则表达式30分钟入门教程》等资料。接下来,我们将重点熟悉JavaScript中RegExp对象的具体实现方式。
RegExp对象详解
二、JavaScript中的正则表达式对象RegExp
1、创建正则表达式:
(1)使用字面量方式:语法格式为 var exp = /pattern/flags;。
A、pattern代表任意有效的正则表达式模式。
B、flags包含三种标志:g表示全局匹配模式、i表示忽略大小写、m表示多行模式。
(2)使用RegExp内置构造函数:语法格式为 var exp = new RegExp(pattern, flags);。
A、使用构造函数时,pattern和flags参数均必须以字符串形式传入。因此,对于正则表达式中的转义字符需要进行双重转义,例如:
| 字面量 | 构造函数 |
| /\[bc\]at/ | "\\[bc\\]at" |
| /\.at/ | "\\.at" |
| /name\/age/ | "name\\/age" |
| /\d.\d{1,2}/ | "\\d.\\d{1,2}" |
| /\w\\helllo\\123/ | "\\w\\\\hello\\\\123" |
说明:在ECMAScript 3标准中,使用字面量创建的正则表达式会共享同一个RegExp实例;而使用new RegExp(pattern,flags)则为每次调用创建新实例。ECMAScript 5标准规定,无论何种方式,每次创建都生成新实例。
2、实例属性:
(1)global:布尔值,指示是否设置了g标志。
(2)ignoreCase:布尔值,指示是否设置了i标志。
(3)multiline:布尔值,指示是否设置了m标志。
(4)lastIndex:整数,表示下一次搜索开始匹配的字符位置,索引从0开始计算。
(5)source:字符串,表示以字面量形式创建的正则表达式模式字符串。即使实例是通过构造函数创建的,该属性存储的依然是字面量形式的字符串模式。
3、实例方法:
(1)exec()方法:
A、该方法接收一个参数,即要应用正则模式的字符串,返回包含第一个匹配项信息的数组;若无匹配则返回null。
B、返回的数组是Array实例,但额外包含input和index属性,分别表示应用正则表达式的原始字符串以及匹配项在字符串中的起始位置。
C、当匹配成功时,返回数组的第1项是与整个模式匹配的字符串,后续项则是与模式中各个分组匹配的字符串(若未定义分组,则返回数组仅包含第1项)。
D、对于exec()方法,即使设置了g标志,每次调用仍只返回一个匹配项。区别在于,设置g标志后,多次调用exec()时搜索起始位置会更新;未设置g标志时,每次调用均从字符串开头开始搜索。
(2)test()方法:
该方法接受一个字符串参数,若匹配成功返回true,否则返回false。
三、实例分析
实战案例分析
下面通过一个源自PhoneGap源码的格式化正则表达式案例进行解析。
代码如下:
var pattern = /(.*?)%(.)(.*)/;
var str = 'lin%%jisong';
var match = pattern.exec(str);
console.info(match.join(','));//lin%%jisong,lin,%,jisong
var pattern2 = /(.*)%(.)(.*)/;
var match2 = pattern2.exec(str);
console.info(match2.join(','));//lin%%jisong,lin%,j,isong分析:此处pattern和pattern2均包含三个分组,其中第2、3个分组的定义相同。第2个分组(.)匹配任意单个非换行字符,第3个分组(.*)以贪婪模式尽可能多地匹配任意非换行字符。pattern中的第1个分组(.*?)以懒惰模式尽可能少地匹配任意非换行字符,而pattern2中的第1个分组(.*)则以贪婪模式尽可能多地匹配。因此,在确保整个模式匹配成功(即需保留一个%字符供正则表达式中的字面量%匹配)的前提下,pattern的第1个分组匹配结果为“lin”,而pattern2的第1个分组匹配结果为“lin%”。基于此逻辑,上述代码的输出结果便清晰可见。
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
