先来看一个例子

这里有一个例子,用来匹配URL的正则表达式。

1
2
3
4
5
6
7
var url = "http://bubuzou.com:80/goodparts?q#fragment";
var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Z-a-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
console.log( parse_url.exec( url ) );
/*
上面这段代码产生的结果如下:
["http://bubuzou.com:80/goodparts?q#fragment", "http", "//", "bubuzou.com", "80", "goodparts", "q", "fragment"]
*/

现在让我们来分解parse_url的各个部分,看看它是如何工作的:

  • ^字符表示字符串的开始
  • (?:([A-Za-z]+):)?这个因子匹配一个协议名,但是只有当它后面跟随:的时候才匹配。(?:...)表示一个非捕获型的分组。后缀?表示这个分组是可选的,表示匹配0次或者1次。
    (...)表示一个捕获型分组。一个捕获型分组会复制它所匹配的文本,并且将其放到result数组里。每个捕获型分组会被指定一个编号。第一个捕获型分组的编号是1,所以该分组所匹配的结果会出现在result[1]中。[...]表示一个字符类。A-Za-z这个字符类包含26个大写字母和26个小写字母。+表示这个字符类会被匹配1次或多次。:会按照字面进行匹配。
  • (\/{0,3})这个因子是捕获分组2。\/表示匹配/(斜杠),它用\来进行转义。{0,3}表示会被匹配0-3次
  • ([0-9.\-A-Z-a-z]+)这个因子是捕获分组3。它会匹配一个主机名,由一个或多个数字、字母,以及.或-组成。
  • (?::(\d+))?这个因子匹配的是端口号。(\d+)是捕获分组4,表示匹配一个或多个数字。
  • (?:\/([^?#]*))?是一个可选的分组,以一个/开始。[^?#]是捕获分组5,以一个^开始表示这个类包含除?#之外的所有字符。*表示匹配0次或多次。
  • (?:\?([^#]*))?是一个以?开始的分组。包含捕获分组6,这个分组包含0个或多个非#的字符
  • (?:#(.*))?这个可选分组是以#开始的,.会匹配除了行结束符以外的所有字符。
  • $表示字符串的结束

所谓正则表达式,就是一种描述字符串结构模式的形式化表达方法。

这是《精通正则表达式》对它的定义。
正则表达式又叫做规则表达式(Regular Expression,简写regexp).
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

正则表达式能干嘛

  • 测试字符串是否满足某种模式。比如字符串内是否出现电话号码模式,又称为数据验证。
  • 替换文本。可以用正则表达式来识别字符串中的特定文本,完全删除或者用其他文本替换它。
  • 提取字符串。基本匹配模式从字符串中提取需要的子字符串。

正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux, Unix等),HP等操作系统,PHP、C#、Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。

正则表达式结构

优先考虑的方法是使用正则表达式字面量:

1
var patt = /pattern/modifiers;

另一种方法是使用RegExp构造器:

1
var patt = new RegExp(pattern, modifiers);

  • pattern(模式) 描述了表达式的模式
  • modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配

修饰符modifiers:

修饰符 描述
i 执行对大小写不敏感的匹配
g 执行全局匹配
m 执行多行匹配
1
2
3
var patt = /hello/ig;
var str = 'Hello world!';
patt.exec( str ); // 将会匹配'Hello'

正则表达因子

一个正则表达式因子可以是一个字符、一个圆括号包围的组、一个字符类或者是一个转义序列。下面这些字符都会按照字面进行处理\ / [ ] ( ) { } ? + * | . ^ $如果你希望这些字符按照字面意思去匹配,那需要在其前面加上\进行转义。

1
2
3
var patt = /\.\d+/;
var str = '-12.568';
patt.exec( str ); // 匹配'.568'

正则表达式特殊字符:

特殊字符 描述
^ 匹配输入字符串开始处的位置;但在中括号表达式中是表示对字符集求反。若要匹配 ^ 字符本身,请使用 \^
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,那么 $ 还匹配 \n\r 前面的位置。若要匹配 $ 字符本身,请使用 \$
() 标记子表达式的开始和结束。可以捕获子表达式以供以后使用。若要匹配这两个字符,请使用 \(\)
* 零次或多次匹配前面的字符或子表达式。若要匹配 * 字符,请使用 \*
+ 一次或多次匹配前面的字符或子表达式。若要匹配 + 字符,请使用 \+
? 零次或一次匹配前面的字符或子表达式,或指示“非贪心”限定符。若要匹配 ? 字符,请使用 \?
. 匹配除换行符 \n 之外的任何单个字符。若要匹配 . 请使用 \
[] 标记中括号表达式的开始。若要匹配这些字符,请使用 \[\]
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,字符n 匹配字符 n\n 匹配换行符。序列 \\ 匹配 \,序列 \( 匹配 (
/ 表示文本正则表达式的开始或结束。若要匹配 / 字符,请使用 \/
{} 标记限定符表达式的开始。若要匹配这些字符,请使用 \{\}
竖线 指出在两个项之间进行选择。要匹配竖线,请使用 \竖线

正则表达式序列

一个正则表达式序列包含一个或多个正则表达式因子。每个因子能选择是否跟随一个量词,这个量词决定了这个因子被允许出现的次数。如果没有量词,则只匹配一次。

1
2
3
var patt = /\d{3}\.\d/;
var str = 'abc1893.65d';
patt.exec( str ); // 匹配'893.6'

正则表达式分支

一个正则表达式分支包含一个或多个正则表达式序列。这些序列被|字符分隔。如果这些序列中的任何一项符合匹配条件,那么这个选择就被匹配。它会按照书写顺序从左到右依次匹配这些序列。

1
2
3
var str = 'information';
str.match( /or|for/ ); // 匹配'for'
str.match( /or|orm/ ); // 匹配'or'

正则表达式分组

正则表达式的分组共有6种。

  • (...)捕获型,捕获型分组是一个被包围在圆括号中的正则表达式分支。任何匹配这个分组的字符都会被捕获。每个捕获分组都将有一个编号。第一个捕获分组的编号是1,以此类推。

    1
    2
    /(:\d+)/.exec( 'bubuzou.com:80/' );
    // 结果是[':80', ':80'],第一个':80'表示整个正则的匹配,第二个':80'表示捕获分组1的匹配
  • (?:...)非捕获型,仅做简单的匹配,并不会捕获所匹配的文本。也不会进行编号。

    1
    /(?::\d+)/.exec( 'bubuzou.com:80/' ); 结果是[':80'],不包含分组捕获。
  • (?=pattern)正向肯定预查。匹配其跟随了pattern的字符串。这不是一个好的特性。

    1
    /window(?=95|98|2000)/.exec( 'window98' ); // 匹配'window'
  • (?!pattern)正向否定预查。匹配其没有跟随了pattern的字符串。这不是一个好的特性。

    1
    /window(?!95|98|2000)/.exec( 'windowNT' ); // 匹配'window'
  • (?<=pattern)反向肯定预查。匹配前面带pattern的字符串。这不是一个好的特性。

    1
    /(?<=95|98|2000)windows/.exec( '95windows' ); // 匹配'windows'
  • (?<!pattern)反向否定预查。匹配前面没有带pattern的字符串。这不是一个好的特性。

RegExp对象方法

方法 描述
regexp.exec(string) 检索字符串中指定的值。如果匹配成功,则返回一个数组。数组中下标为0的值表示匹配的子字符串,下标为1的值是分组1捕获的文本。如果匹配失败,则会返回null.
regexp.test(string) 检索字符串中指定的值。返回true或false。text方法中不需要对regexp进行全局匹配的配置,因为结果都一样。
string.match(regexp) 获取匹配结果。如果没有g标识,则结果和regexp.exec(string)一样。如果有g标识,则返回包含所有匹配结果(除了分组捕获之外)的数组
string.replace(searchValue, replaceValue) replace方法对字符串执行查找和替换工作,并返回一个新的字符串。参数searchValue可以是一个字符串或者正则表达式。如果是字符串,则在字符串中第一次出现的地方被替换。如果是正则表达式且带有g,则会替换所有匹配,如果没有g则只会替换第一个匹配。replaceValue可以是一个字符串或者一个函数。如果是一个函数则有特别含义。如果是一个函数,则每遇到一个匹配函数就会被调用一次,而函数返回的字符串将作为替换的文本。
string.search(regexp) 和indexOf方法类似,只是它接受的参数是一个正则表达式而非字符串。如果找到匹配,则返回第一个匹配的首字符的位置,没找到就返回-1
string.split(separator, limit) 把string分割成片段来创建一个字符串数组。limit可以限制分割的数量。separator可以是字符串或正则表达式。

regexp.exec(string):

1
2
3
4
5
6
7
8
9
// RegExpObject.exec(string);
var str="user1abcuser2abc",
patt=/user\d/g,
result;
while ( ( result = patt.exec( str ) ) ) {
console.log( result );
}
// 第一次:["user1", index: 0, input: "user1abcuser2abc"]
// 第二次:["user2", index: 8, input: "user1abcuser2abc"]


如果regexp带有g标识,那么查找不是从这个字符串的起始位置开始,而是从regexp.lastIndex位置开始。如果匹配成功,那么regexp.lastIndex将被设置为该匹配后第一个字符的位置。不成功的匹配会将regexp重新设置为0。

regexp.test(string):

1
/Hello/i.test( 'hello world' ); // true

string.match(regexp):

1
2
'user1abcuser2abc'.match( /user\d/g ); // ['user1', 'user2']
'user1abcuser2abc'.match( /user\d/ ); // ['user1']

string.replace(searchValue, replaceValue):

1
2
3
var patt = /\((\d{3})\)/g,
str = '(555)666-1212'.replace(patt, '$1-');
console.log(str); // 结果:'555-666-1212'

美元符号序列 替换对象
$$ $
$& 整个匹配的文本
$number 分组匹配的文本
$` 匹配之前的文本
$’ 匹配之后的文本

string.search(regexp):

1
'hello world'.search( /world/ ); // 6

string.split(separator, limit):

1
2
'123456'.split('', 3); // ["1", "2", "3"]
'last, first, middle'.split(/\s*,\s*/); // ['last', 'first', 'middle']

正则表达式字符表

量词:

量词 描述
* 零次或多次匹配前面的字符或子表达式。例如,zo 匹配 z 和 zoo。 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,zo+ 匹配 zo 和 zoo,但不匹配 z。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,do(es)? 匹配 do 或 does 中的 do。? 等效于 {0,1}。
{n} n是非负整数。正好匹配 n 次。例如,o{2} 不匹配 Bob 中的 o,但匹配 food 中的两个 o。
{n,} n 是非负整数。至少匹配 n 次。例如,o{2,} 不匹配 Bob 中的 o,而匹配 foooood 中的所有 o。o{1,} 等效于 o+。o{0,} 等效于 o*。
{n,m} m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,o{1,3} 匹配 fooooood 中的头三个 o。o{0,1} 等效于 o?。注意:您不能将空格插入逗号和数字之间。

方括号:方括号用于查找某个范围内的字符

表达式 描述
[abc] 查找方括号之间的任何字符
[^abc] 查找任何不在方括号之间的字符
[0-9] 查找任何从 0 至 9 的数字
[a-z] 查找任何从小写 a 至小写 a 的字符
() 匹配一个子表达式的开始和结束位置

元字符:拥有特殊含义的字符

元字符 描述
. 查找单个字符,除了换行和行结束符
\w 查找单词字符
\W 查找非单次字符
\b 匹配一个字的边界,即字与空格间的位置
\B 非字符边界匹配
\d 查找数字
\D 查找非数字字符
\s 查找空白字符
\S 查找非空白字符