JS正则

Posted by Zxd on September 06, 2017
  1. 获取url中参数值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//new RegExp("regexp","i") i修饰符表示对大小写不敏感

function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i")
var url = "?wd=window.onload&rsv_spt=1&rsv_iqid=0xd1242b8400000885&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8"
var r = url.substr(1).match(reg);
// var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
// unescape() 解码
// r[2] 分组捕获中的第二组
}
return null;
}

var queryString = getQueryString('rsv_iqid')
console.log(queryString)
  • window.location.search 返回?xx=ddd&cc=bbb类似,以?开头

str.substr(start[,length])

  • start : number
    • 要抽取的子串起始下标,如果是负数,从尾部开始算,-1表示最后一位.
  • length : number
    • 可选 要取多少个字符,不指定,返回start到结尾
1
2
3
4
5
6
7
8
var str = "abcdefghij";

console.log("(1,2): " + str.substr(1,2)); // (1,2): bc
console.log("(-3,2): " + str.substr(-3,2)); // (-3,2): hi
console.log("(-3): " + str.substr(-3)); // (-3): hij
console.log("(1): " + str.substr(1)); // (1): bcdefghij
console.log("(-20, 2): " + str.substr(-20,2)); // (-20, 2): ab
console.log("(20, 2): " + str.substr(20,2)); // (20, 2):

str.substring(indexStart[, indexEnd])

substring 提取从 indexStart 到 indexEnd(不包括)之间的字符

  • indexStart
    • 开始索引
  • indexEnd
    • 可选,结束索引,如果省略, substring提取字符一直到字符串末尾
  • 如果任意参数小于0或为NaN,则被当作0
  • 如果indexStart大于indexEnd,则执行效果相当于两个参数调换了一样

str.match(regexp)

  • regexp
    • 一个正则表达式对象.如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj)将其转换为RegExp,如果未传参,则会得到包含空字符串的Array: [""]
  • 返回值
    • array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var str = 'For more information, see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);

console.log(found);

0:"see Chapter 3.4.5.1"
1:"Chapter 3.4.5.1"
2:".1"
groups:undefined
index:22
input:"For more information, see Chapter 3.4.5.1"
length:3

// 'see Chapter 3.4.5.1' 是整个匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕获。
// '.1' 是被'(\.\d)'捕获的最后一个值。
// 'index' 属性(22) 是整个匹配从零开始的索引。
// 'input' 属性是被解析的原始字符串。
  • 正则表示式包含i标志,大小写会被忽略
1
2
3
4
5
6
7
// match 使用全局(global)和忽略大小写(ignore case)标志
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);

console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
  • var regexp = /[A-E]/gi;/gi,g全局匹配,找到所有匹配,而不是第一个匹配后停止,i忽略大小写

RegExp 正则表达式

RegExp构造函数创建了一个正则表达式对象,用于将文本与一个模式匹配。

/pattern/flags

new RegExp(pattern [, flags])

  • pattern
    • 正则表达式文本
  • flags
    • 如果指定,有以下任意组合
    • g 全局匹配,找到所有匹配,而不是在第一个匹配后停止
    • i 忽略大小写
    • m 多行,将开始和结束字符(^和$)视为在多行上工作
    • u Unicode; 将模式视为Unicode序列点的序列
    • y 粘性匹配;
1
2
/ab+c/i;
new RegExp('ab+c', 'i');

有两种方法来创建一个RegExp对象:一个是字面量,二是构造函数,要指示字符串,字面量的参数不适用引号,二构造函数的参数使用引号

  • 当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)。比如,以下是等价的:
1
2
var re = new RegExp("\\w+");
var re = /\w+/;
  • \ 向右,反斜杠

字符类别(Character Classes)

  • . 点号,匹配任意单个字符,但是行结束符除外:\n \r \u2028 \u2029,\n换行,\r回车
1
`/.y/` 匹配 "yes make my day" 中的 "my" 和 "ay",但是不匹配 "yes"
  • \d 匹配任意数字 等价于[0-9]
1
/\d/ 或 /[0-9]/ 匹配 "B2 is the suite number." 中的 '2'
  • \D 匹配任意一个不是数字的字符 等价于[^0-9]
1
/\D/ 或 /[^0-9]/ 匹配 "B2 is the suite number." 中的 'B'
  • \w 匹配任意字母表中的字母 数字下划线 (单词字符word)等价于[A-Za-z0-9_]
1
2
/\w/ 匹配 "apple" 中的 'a',"$5.28" 中的 '5' 和 "3D" 中的 '3'
// 返回第一个
  • \W 匹配任意不是字母 数字 下划线的字符 等价于[^A-Za-z0-9_]
1
/\W/ 或 /[^A-Za-z0-9_]/ 匹配 "50%" 中的 '%'
  • \s 匹配一个空格符,包括空格,制表符,换页父,换行符和其他Unicode空格
1
/\s\w*/ 匹配 "foo bar" 中的 ' bar'
  • \S匹配一个非空白符.
1
/\S\w*/ 匹配 "foo bar" 中的 'foo'
  • \t 匹配一个水平制表符(tab)
  • \r 匹配一个回车符(carriage return)
  • \n 匹配一个换行符(linefeed)
  • \v 匹配一个垂直制表符(vertical tab)
  • \f 匹配一个换页符(form-feed)
  • \ 转义字符
    1
    2
    /a*/ 意味着 0 或多个 "a"
    /a\*/匹配 'a*' 匹配字面意义的*

字符集合(Character Sets

  • [xyz] 一个字符集合也叫字符组.匹配集合中的任意一个字符.可以使用连字符-指定一个范围

    1
    [abcd] 等价于 [a-d],匹配"brisket"中的'b'和"chop"中的'c'
  • [^xyz] 反义字符组,匹配任意不在括号内的字符

    1
    [^abc] 等价于 [^a-c]。 第一个匹配的是 "bacon" 中的'o' 和 "chop" 中的 'h'

边界(Boundaries)

  • ^ 匹配输入开始.

    1
    /^A/ 不匹配 "an A" 中的 "A",但匹配 "An A" 中的 "A"
  • $ $匹配输入结尾.

    1
    /t$/ 不匹配 "eater" 中的 "t",但匹配 "eat" 中的 "t"
  • \b 匹配一个零宽单词边界(zero-width word boundary),如一个字母与一个空格之间

    1
    /\bno/ 匹配 "at noon" 中的 "no",/ly\b/ 匹配 "possibly yesterday." 中的 "ly"
  • \B 匹配一个零宽非单词边界(zero-width non-word boundary),如两个字母之间或两个空格之间

    1
    /\Bon/ 匹配 "at noon" 中的 "on",/ye\B/ 匹配 "possibly yesterday." 中的 "ye"

分组(Grouping)与反向引用(back references)

  • 使用()把单独的项组合成子表达式,以便可以像处理一个独立的单元那样用| * + ? {}等来对单元内的项进行处理
  • (x) 匹配x并且捕获匹配项,这被称为捕获括号(capturing parentheses)

    1
    2
    3
    /(foo)/ 匹配且捕获 "foo bar." 中的 "foo"。被匹配的子字符串可以在结果数组的元素 [1], ..., [n] 中找到,或在被定义的 RegExp 对象的属性 $1, ..., $9 中找到。

    捕获组(Capturing groups)有性能惩罚。如果不需再次访问被匹配的子字符串,最好使用非捕获括号(non-capturing parentheses)
  • \n n是一个正整数. 一个反向引用(back reference), 指向正则表达式中第n个括号(从左开始数)中匹配的子字符串

    1
    /apple(,)\sorange\1/ 匹配 "apple, orange, cherry, peach." 中的 "apple,orange,"
  • (?:x) 匹配 x 不会捕获匹配项.这被称为非捕获括号(non-capturing parentheses),匹配项不能够从结果数组的元素 [1], …, [n] 或已被定义的 RegExp 对象的属性 $1, …, $9 再次访问到.

数量词(Quantifiers)

  • x* 匹配前面的模式x 0次或多次

    1
    /bo*/ 匹配 "A ghost booooed" 中的 "boooo","A bird warbled" 中的 "b",但是不匹配 "A goat grunted"
  • x+ 匹配前面的模式x 1次或多次.等价于{1,}

    1
    /a+/ 匹配 "candy" 中的 "a","caaaaaaandy" 中所有的 "a"
  • x*? x+? 和上面的*`+`一样匹配前面的模式x,然而匹配的是最小可能匹配

    1
    /".*?"/ 匹配 '"foo" "bar"' 中的 '"foo"',而 * 后面没有 ? 时匹配 '"foo" "bar"'
  • x? 匹配前面的模式x 0次或1次

    1
    /e?le?/ 匹配 "angel" 中的 "el","angle" 中的 "le"

如果在数量词 *+?{}, 任意一个后面紧跟该符号?,会使数量词变为非贪婪( non-greedy) ,即匹配次数最小化。反之,默认情况下,是贪婪的(greedy),即匹配次数最大化。

  • x(?=y)只有当x后紧跟着y时,才匹配x

    1
    2
    3
    /Jack(?=Sprat)/ 只有在 'Jack' 后面紧跟着 'Sprat' 时,才会匹配它
    /Jack(?=Sprat|Frost)/ 只有在 'Jack' 后面紧跟着 'Sprat' 或 'Frost' 时,才会匹配它
    然而,'Sprat' 或 'Frost' 都不是匹配结果的一部分
  • x(?!y) 只有当 x 后面不是紧跟着 y 时,才匹配 x

    1
    2
    只有当 x 后面不是紧跟着 y 时,才匹配 x
    /\d+(?!\.)/.exec("3.141") 匹配 141 而不是 3.141
  • x|y 匹配xy

    1
    /green|red/ 匹配 "green apple" 中的 ‘green',"red apple." 中的 'red'
  • x{n}
    n 是一个正整数。前面的模式 x 连续出现 n 次时匹配

    1
    /a{2}/ 不匹配 "candy," 中的 "a",但是匹配 "caandy," 中的两个 "a",且匹配 "caaandy." 中的前两个 "a"
  • x{n,} n 是一个正整数。前面的模式 x 连续出现至少 n 次时匹配

    1
    /a{2,}/ 不匹配 "candy" 中的 "a",但是匹配 "caandy" 和 "caaaaaaandy." 中所有的 "a"
  • x{n,m} n 和 m 为正整数。前面的模式 x 连续出现至少 n 次,至多 m 次时匹配

    1
    2
    /a{1,3}/ 不匹配 "cndy",匹配 "candy," 中的 "a","caandy," 中的两个 "a",匹配 "caaaaaaandy" 中的前面三个 "a"
    注意,当匹配 "caaaaaaandy" 时,即使原始字符串拥有更多的 "a",匹配项也是 "aaa"

断言(Assertions)

  • x(?=y) 仅匹配被y跟随的x

    1
    /Jack(?=Sprat)/,如果"Jack"后面跟着sprat,则匹配之
  • x(?!y) 仅匹配不被y跟随的x

    1
    2
    /\d+(?!\.)/ 只会匹配不被点(.)跟随的数字
    /\d+(?!\.)/.exec('3.141') 匹配"141",而不是"3.141"

For example

1. 使用正则改变数据结构

  • 这里$1$2指明括号里先前的匹配
    1
    2
    3
    4
    var re = /(\w+)\s(\w+)/;
    var str = "John Smith";
    var newstr = str.replace(re, "$2, $1");
    print(newstr); // "Smith, John"

2. 从 URL 中提取子域名

1
2
3
4
5
6
7
8
var url = "http://xxx.domain.com";
print(/[^.]+/.exec(url)[0].substr(7)); // prints "xxx"

var url = "https://xxx.domain.com";
var reg = /[^.]+/ // 匹配[^.] 任意不在括号内的数,`.`,一次或者多次
var reg2 = new RegExp('[^.]+','i')
console.log(reg.exec(url)[0].substr(8)) // substr(8) 第8位开始
console.log(url.match(reg2))

分组捕获

  • 0组始终代表整个表达式
  • 从左到右计算其开括号来编号
  • 如(A)(B(C))中存在4组
0 (A)(B(C))
1 (A)
2 (B(C))
3 (c)