正则表达式最后一站

javascript进击

Posted by Felix on May 8, 2018

正则表达式

正则表达式是执行字符串模式匹配的强大工具

创建正则表达式有两种方式,一种是字面量的方式创建,一种是使用RegExp构造函数创建

var reg1 = /pattern/flags;
var reg2 = new RegExp(pattern,flags);

其中模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、向前查找以及反向引用。 每个正则表达式都可带有以或多个标志(flags),用以表明正则表达式的行为。

注:flags为可选项,表示匹配模式,一共有三种标志

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

RegExp的实例属性

每个RegExp实例对象都会存在下列属性:

  • global : 布尔值,表示是否设置了g标志
  • ignoreCase : 布尔值,表示是否设置了i标志
  • multiline : 布尔值,表示是否设置了m标志
  • lastIndex : 整数,表示开始搜索下一个匹配项的字符位置,从0算起
  • source : 正则表达式字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回
var reg = /\[hello\]regexp/i;
console.log(reg.global); // false
console.log(reg.ignoreCase); // false
console.log(reg.multiline);  // false
console.log(reg.lastIndex);  // 0
console.log(reg.source);   // \[hello\] regexp
var reg1 = new RegExp('\\[hello\\] regexp','ig');
console.log(reg1.global); // true
console.log(reg1.ignoreCase); // true
console.log(reg1.multiline);  // false
console.log(reg1.lastIndex);  // 0
console.log(reg1.source);  // \[hello\] regexp
// 拓展 /的转义?
var reg2 = /\\/;
// \\ 在正则表达式中需要转义\\ 表示 \
var reg3 = new RegExp('\\\\');
// 在构造函数模式中 \\\\ 表示正则表达式匹配字符串 \,因为字符串引擎和正则表达式引擎先后进行转义
var str = '\\2';
// \ 在正则表达式中需要转义 \\ 表示 \
console.log(reg2.test(str));  // true

RegExp的实例方法

  • pattern.exec(str) 捕获数组,返回一个包含匹配信息的数组或者null;

非全局模式下,如果字符串中包含与模式匹配的多个子字符串,只会返回第一个匹配项的结果,返回的数组下标为0的位置表示匹配到的字符串,其余位置表示匹配到的捕获组的信息;

全局模式下,如果依次执行exec方法,依次返回每一个匹配项信息的数组。

var reg = /<(\/?)(\w+)([^>]*?)>/,
str = "22<div class='hello'><b>hello</b><i>regexp</i><div/>";
var matches  = reg.exec(str);
console.log(matches[0]) // <div class='hello'>
console.log(matches[1]) // ''
console.log(matches[2]) // div
console.log(matches[3]) //  class='hello'
console.log(matches.index) // 2
console.log(reg.lastIndex); // 0 如果执行全局匹配
console.log(matches.input) // str
var reg =  /<(\/?)(\w+)([^>]*?)>/g;
var matches = reg.exec(str); // reg.lastIndex为21
var matches = reg.exec(str);
// 依次捕获满足条件的匹配项 reg.lastIndex一直在变化
  • Pattern.test(str) 用于检测字符串中是否存在与模式匹配的字符串,匹配成功返回true,失败返回false。

RegExp的构造函数属性

构造函数静态属性 ,分别有一个长属性名和一个短属性名(Opera不支持短属性名)

长属性名 短属性名 说明
input $_ 最近一次要匹配的字符串
lastMatch $& 最近一次的匹配项
lastParen $+ 最近一次匹配的捕获组
leftContext $` input字符串中lastMatch之前的文本
multiline $* 布尔值,表示是否所有表达式都使用多行模式
rightContext $’ input字符串中lastMatch之后的文本
var pattern = /(.)or/,
str = 'this is a normal string or meaningful';
if(pattern.test(str)){
    console.log(RegExp.input); // this is ....
    console.log(RegExp.lastMatch); // nor
    console.log(RegExp.lastParen); // n
    console.log(RegExp.leftContext); // this is a
    console.log(RegExp.rightContext); // mal string or meaningfull
    
    console.log(RegExp['$_']);
    console.log(RegExp['$&']);
    console.log(RegExp['$+']);
    console.log(RegExp['$`']);
    console.log(RegExp['$\'']);
    console.log(RegExp.$1); // n
    // $1 --- $9 表示最近一次匹配的捕获组的字符串的自动填充,也就是()括号内匹配的字符串
}

用于模式匹配的String方法

  • str.search(pattern)

    返回与第一个与之匹配的子串的起始位置,如果找不到匹配的子串返回-1;

    注:search()参数不是正则表达式,它会首先RegExp构造方法将它转化为正则表达式;不支持全局检索,以为忽略修饰符 g

  • str.replace(subStr | pattern, replaceStr | function)

第一个参数是正则表达式或者是字符串,第二个参数是要替换的字符串。如果第一个参数是正则表达式,直接进行模式匹配,若为字符串,则会检索整个字符串进行替换,而不会转化为正则表达式。

  • str.match(pattern)

    方法接收一个正则表达式,如果是在全局模式匹配下,匹配失败返回null,匹配成功会返回一个数组,包含所有匹配的值;如果是非全局模式,则返回第一个匹配项数组信息,数组中第一个元素为匹配字符串,余下为匹配的捕获组,另外这个数组还有两个属性,index和input,index表示匹配字符串的开始索引,input表示匹配的字符串。

  • str.split(pattern | subStr,[howmany])

    可以接收两个参数,第二个参数可选,表示返回数组的最大长度。其中第一个参数是指定的分隔符,可以使正则表达式或者是字符串。

精准匹配

精准匹配可以理解为一对一匹配,即正则表达式中中的术语与字符串中的字符对应

#### 匹配一类字符

注:

. 除了换行符和其他Unicode行终止符之外的任意字符。

.不能匹配的字符只要有\r回车符 \n换行符 \u2028行分割符 ` \u2029`段分隔符

\w 任意ASCII字符组成的单词,等价于[a-zA-Z0-9_]

\W 任意不是ASCII字符组成的单词,等价于[^-zA-Z0-9_]

\b 单词边界 \t 水平制表符 \f换页符 \r 回车 \n换行

转义

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

( [ { \ ^ $ | ? * + . } ] )
有时候需要双重转义:
/\[abc\]/   -----   new RegExp("\\[abc\\]")
/\\/  ----- new RegExp("\\\\")
    var reg1 = /\d/ // 匹配 2
    var reg2 = /\\d/ // 匹配 '\\d'
    var reg3 = /\\\d/ //匹配 '\\1'
    var reg4 = /\\\\d/ // 匹配 '\\\\d'
    var reg5 = new RegExp('\d') //匹配 'd'
    var reg6 = new RegExp('\\d') // 匹配 1
    var reg7 = new RegExp('\\\d') //匹配 1
    var reg8 = new RegExp('\\\\d') //匹配 '\\d'
    var reg9 = new RegExp('\\\\\d') //匹配 '\\d'
    var reg10 = new RegExp('\\\\\\d') //匹配 '\\1'
    //    var reg = new RegExp('\[abc\]'); // [abc];
    //    var str = 'ab'
    //    console.log(reg.test(str))  // true
    //    var reg2 = new RegExp('\\[abc\\]'); // 表示字符串 '[abc]'
    //    var str2 = '[abc]a';
    //    console.log(reg2.test(str2)); // true  
    // 总结:正则表达式匹配的结果根据解析后字符串转义字符\有关系 \的个数为单数 匹配最后一个\与d组成数字 
    // 其他的\也要加上,\的数量为双数直接匹配这串字符串;

匹配开始和结尾

  • 匹配一个字符串的开始使用符号(^),例如: /^java/表示匹配已”java”开头的字符串
  • 匹配一个字符串的结尾使用符号(),例如:/script),例如:/script/表示匹配已”script”结尾的字符串
  • 如果一个正则表达式中即出现了(^)又出现了(),表示必须匹配整个候选字符串

重复

贪婪重复

匹配尽可能多的匹配,/a+/ 表示至少匹配一个’a’字符,有多少个就匹配多少个。

   ` {x,y}`  匹配至少x次 最多y次

    `{x,}`   匹配至少x次

    `{x}`  匹配x次

    `?` 匹配0或者1次

    `+` 至少匹配一次

    `*` 匹配0次或多次

非贪婪模式

  在贪婪模式上后面加个? 表示尽可能少的匹配

   `{x,y}?`  `{x,}?` `{x}?`  `??` `+?` `*?`

分组问题

1.分组:使用()表示分组,表示匹配一类字符串,例如:/(\w\s)+/表示匹配一个或者多个以字母和空格组合出现的字符串。

2.捕获组:用于模式匹配之后,匹配到的元组就被成为捕获组。捕获组对应着括号的数量,分别使用$1,$2$99$x表示匹配到的捕获组,另外可以使用\1,\2\99\x表示引用捕获组。

3.非捕获组:若希望以()分组的元组在匹配的时候不被捕获,可以使用如下形式:

(?:str|pattern)

var str = "2017023",
     reg1 = /(?:\d{4})(\d{2})/;
     console.log(str.match(reg1));
     // (2) ["201702", "02", index: 0, input: "2017023"]
     // 忽略了匹配组 (\d{4})

断言

正则表达式中的断言大体分为两类,先行断言与后发断言;在每一种断言中又分为正环顾和负环顾,因此一共有四种断言形式。

(?=exp)匹配的位置前面能匹配到的值。

(?<=exp)匹配的位置后面能匹配到的值

(?!exp)匹配的位置后面不能是exp

(?<!exp)匹配值前面不能是exp

####