JavaScript正则表达式详解

来源:互联网 发布:unity3d spine 编辑:程序博客网 时间:2024/04/29 10:50

JavaScript正则表达式详解

正则表达式(Regular Expression)使用单个字符串来描述,匹配一系列符合某个句法规则的字符串。

一、RegExp对象

实例化RegExp对象方法:

(1)字面量,如: var reg = /\bbis\b/g;

(2)构造函数, 如:new reg = new RegExp(‘\bis\b’, ‘g’);

二、正则表达式语法及用法

一个正则表达式就是由普通字符以及特殊字符(称为元字符)组成的文字模式,该模式描述在查找文字主体时待匹配的一个或多个字符串,正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

1、修饰符

g : 表示全局匹配模式。

i : 表示匹配时忽略大写。

m : 表示多行匹配。

2、元字符

(1)原意文本字符,如:a,A等。

(2)元字符,元字符是正则表达式中有特殊含义的非字母字符,有: * + ? $ ^ . | \ ( ) { } [ ]

这里写图片描述

3、字符类

一般情况下,正则表达式一个字符对应字符串的一个字符,但是可以用 [ ] 来构建一个简单的类。

类: 这里的类指符合某些特性的对象,一个泛指,而不是特指某个字符。

例如: [abc]把字符a或b或c归为一类,表达式可以匹配这类的字符。

'a1b2c3d4'.replace(/[abc]/g, '啦')  // "啦1啦2啦3d4"

字符类取反: 使用元字符^创建反向类/负向类,反向类就是指不属于某类的内容,例如:[^abc]表示不是字符a或b或c的内容。

'a1b2c3d4'.replace(/[^abc]/g, '啦') // "a啦b啦c啦啦啦"

4、范围类

使用[a-z]来连接两个字符表示从a到z的任意字符,包含a和z本身。

    'a1b2c3d4'.replace(/[a-z]/g, '啦') // "啦1啦2啦3啦4"    'Za1W7b2M5c3Q8dA4'.replace(/[a-zA-Z]/g, '啦') // "啦啦1啦7啦2啦5啦3啦8啦啦4"    '2017-08-21'.replace(/[0-9]/g, 'X') // "XXXX-XX-XX"    '2017-08-21'.replace(/[0-9-]/g, 'X') // "XXXXXXXXXX"

5、预定义类

这里写图片描述

例如:
var re=/^[^\d]\w+/g 在这个表达式中,出现了两次“^”,第一个“^”,代表匹配字符串的开头,第二个“^”,代表匹配非方括号中的所有字符。

6、边界匹配符

这里写图片描述

使用示例:

    'this is an apple'.replace(/is/g, '嗨') // "th嗨 嗨 an apple"    'this is an apple'.replace(/\bis\b/g, '嗨')  // "this 嗨 an apple"    'this is an apple'.replace(/\Bis\b/g, '嗨') // "th嗨 is an apple"    '@123@abc@ABC@'.replace(/@./g,'哈') // "哈23哈bc哈BC@"    '@123@abc@ABC@'.replace(/^@./g,'哈') // "哈23@abc@ABC@"    '@123@abc@ABC@'.replace(/.@/g,'哈') // "@12哈ab哈AB哈"    '@123@abc@ABC@'.replace(/.@$/g,'哈') // "@123@abc@AB哈"    '@123@abc@ABC@'.replace(/^@\d/g,'哈') // "哈23@abc@ABC@"

7、重复类(量词)

这里写图片描述

贪婪模式:尽可能多的匹配,直到失败,正则表达式默认就是贪婪模式。

例如:\d{3,6},要求匹配数字出现3到6次,那么默认的贪婪模式就会找到最大的6次,然后匹配

    '12345678'.replace(/\d{3,6}/g,'啦')  // "啦78"

非贪婪模式:让正则表达式尽可能少的匹配,也就是说,一旦成功匹配就不再继续尝试了,实现方式就是使用?
例如:

    '12345678'.replace(/\d{3,6}?/g,'啦') // "啦啦78"

8、分组

使用()可以达到分组的功能,从而可以使得量词作用于分组。

    // 未使用分组和使用分组    'a1b2c3d4'.replace(/[a-z]\d{3}/g, '哈')   // "a1b2c3d4"    'a1b2c3d4'.replace(/([a-z]\d{3})/g, '哈') // "a1b2c3d4"

忽略分组:当不需要捕获分组时候,只需要在分组上加 ?: 就可以了。

9、反向引用

利用分组()和$,可以实现反向引用,例如将:2017-08-21变成 21-08-2017等。

示例:

'2017-08-21'.replace(/\d{4}-\d{2}-\d{2}/g, '$1')             // "$1"'2017-08-21'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$1')       // "2017"'2017-08-21'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2-$3-$1') //"08-21-2017"'2017-08-21'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2/$3/$1') // "08/21/2017"

10、前瞻

正则表达式从文本头部向尾部开始解析,文本尾部方向,称为“前”,前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言。

后顾/后展方向相反,但是JavaScript不支持后顾。

符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配。

这里写图片描述

例如:

    'a1*2#3'.replace(/\w(?=\d)/g, '啦') // "啦1*2#3"    'a1*2#3A6&Z'.replace(/\w(?=\d)/g, '啦') //"啦1*2#3啦6&Z"    'a1*2#3a6&z'.replace(/\w(?=\d)/g, '啦') // "啦1*2#3啦6&z"    'a2*34vv'.replace(/\w(?=\d)/g, '啦') // "啦2*啦4vv"    'a2*34vv'.replace(/\w(?!\d)/g, '啦') // "a啦*3啦啦啦"

符号 | : 表示”或”的意思

    'AngleDevil'.replace(/Angle|Devil/g, '哈')  // "哈哈"    'AngleDevilCevil'.replace(/De|Ce/g, '哈')   // "Angle哈vil哈vil"    'AngleDevilCevil'.replace(/Angle(De|Ce)vil/g, '哈')    // "哈Cevil"    'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g, '哈')  // "哈哈"

三、RegExp对象属性

RegExp的每个示例都有下列的属性:

global: 是否全局搜索,默认是falseignoreCase: 是否区分大小写,默认是falsemultiline: 是否多行搜索,默认是falselastIdex: 是当前表达式匹配内容的最后一个字符的下一个位置source: 正则表达式的文本字符串,按照字面量形式而非传入构造函数中的字符串模式返回

结合示例理解:

    var reg1 = /\w[abc]/im;    console.log(reg1.global);      // false    console.log(reg1.ignoreCase);  // true    console.log(reg1.multiline);   // true    console.log(reg1.lastIndex);   // 0    console.log(reg1.source);      // "\w[abc]"    var reg2 = new RegExp('\w[abc]','g')    console.log(reg2.global);      // true    console.log(reg2.ignoreCase);  // false    console.log(reg2.multiline);   // false    console.log(reg2.lastIndex);   // 0    console.log(reg2.source);      // "w[abc]"

四、RegExp对象方法

(1)RegExp.prototype.test(str)

test()方法用于测试字符串参数中是否存在正则表达式的字符串,如果存在返回true,否则返回false

    var reg3 = /\w/;    var reg4 = /\w/g;    console.log(reg3.test('ab')); // true    console.log(reg3.test('ab')); // true    console.log(reg3.test('ab')); // true    console.log(reg4.test('ab')); // true    console.log(reg4.test('ab')); // true    console.log(reg4.test('ab')); // false    console.log(reg4.test('ab')); // true    console.log(reg4.test('ab')); // true    console.log(reg4.test('ab')); // false    while(reg4.test('ab')){    console.log(reg4.lastIndex); // 分别输出 1 2    }

说 明: 使用test()方法时,如果是在全局模式匹配时(有g),当匹配的次数大于传入的字符串的长度时,会返回false,但是接着下一次又会是true,一直重复,这是由于lastIndex保存的是匹配结果的最后一个字符的下一个字符。

(2) RegExp.prototype.exec(str)

exec()方法使用正则表达式模式对字符串进行搜索,并将更新全局RegExp对象的属性以及返回匹配的结果,如果没有匹配的文本返回null,否则返回一个数组:index 表示匹配文本的第一个字符的位置, input是存放被检索的字符串

非全局调用时,如果调用exec()方法,返回的数组中:
第一个元素是与正则表达式相匹配的文本,
第二个元素是与RegExp对象的第一个子表达式匹配的文本(如果有的话),
第三个元素是与RegExp对象的第二个子表达式匹配的文本(如果有的话),一次类推

var reg5 = /\d(\w)\d/;var reg6 = /\d(\w)(\w)\d/g;var str5 = '$1a2b3c4d5e';var str6 = '$1az2bb3cy4dd5ee';var res5 = reg5.exec(str5); var res6 = reg6.exec(str6);console.log(res5); // ["1a2", "a"]console.log(res6); // ["1az2", "a", "z"]console.log(reg5.lastIndex + ' ' + res5.index + ' ' + res5.input + ' ' + res5.toString()); // "0 1 $1a2b3c4d5e 1a2,a"console.log(reg6.lastIndex + ' ' + res6.index + ' ' + res6.input + ' ' + res6.toString()); // "5 1 $1az2bb3cy4dd5ee 1az2,a,z"

RegExp的实例继承的ToString()和toLocalString()方法都会返回正则表达式的字面量,与创建正则表达式的方方式无关。

五、可以使用正则表达式的字符串方法

(1) String.prototype.search(reg)

search()方法用于检索字符串中指定的字符或检索与正则表达式相匹配的子字符集,返回第一个匹配结果的index,如果没查到则返回-1.

search()方法对于有标志g时,会忽略,始终是从字符串的开始进行检索。

例如:

    'a1b2c3c2b1a'.search('1')    'a1b2c3c2b1a'.search(/1/)    'a1b2c3c2b1a'.search(/1/g)    // 结果都是:1

(2) String.prototype.match(reg)

match()方法将检索字符串,以找到一个或多个与regexp匹配的文本。

非全局调用时:

如果regexp没有标志g,那么match()方法只执行一次匹配,失败返回null,成功时返回一个数组,数组的第一个元素是匹配的文本,其余的元素存放的是与正则表达式的子表达式的文本,此外,返回的数组还有2个对象属性: index 表示匹配文本的起始字符在字符串中的位置, input表示对stringObject的引用。

全局调用时:

如果regexp有标志g,则match()方法执行全局检索,找到字符串中所有匹配子字符集,失败返回null,如果找到了一个或多个匹配子串,则返回一个数组,数组存放的是字符串中所有匹配的子串,没有index或input属性。

var reg7 = /\d(\w)\d/;var reg8 = /\d(\w)\d/g;var str7 = '$1a2b3c4d5e';var res7 = str7.match(reg7);var res8 = str7.match(reg8);console.log(res7); // ["1a2", "a"]console.log(res8); // ["1a2", "3c4"]console.log(res7.index + ' ' + res7.input + ' ' + reg7.lastIndex); // "1 $1a2b3c4d5e 0"console.log(res8.index + ' ' + res8.input + ' ' + reg8.lastIndex); // "undefined undefined 0"

(3) String.prototype.split(reg)

split()方法一般用于把字符串分割为字符数组,在一些复杂的情况下也可以使用正则表示式来解决。

    'a,b,c,d'.split(',')      // ["a", "b", "c", "d"]    'a1b2c3d4e'.split(/\d/g)  // ["a", "b", "c", "d", "e"]    'a,b,c,d'.split(/,/)      // ["a", "b", "c", "d"]

(4) String.prototype.replace()

形式:

    String.prototype.replace(str, replaceStr)    String.prototype.replace(reg, replaceStr)    String.prototype.replace(reg, function)

function的参数:function会在每次匹配替换的时候调用,有4个参数

第一个: 匹配字符集第二个: 正则表达式分组内容,没有分组则没有该参数第三个:匹配项在字符串中的index第四个: 原字符串
'a1b1c1'.replace('1', '哈')  // "a哈b1c1"'a1b1c1'.replace(/1/g, '哈') // "a哈b哈c哈"'a1b1c1'.replace(/1/, '哈')  // "a哈b1c1"'a1b2c3d4e5'.replace(/\d/g, function(match, index, origin){  console.log(index);  return parseInt(match) + 1;})// 每行一次输出 1 3 5 7 9 最后一行是: "a2b3c4d5e6"'a1b2c3d4e5'.replace(/(\d)(\w)(\d)/g, function(match, group1, group2, group3, index, origin){  console.log(match);  return group1 + group3;})// 输出3行,每行分别是: "1b2"   "3d4"   "a12c34e5"

至此,正则表达式先介绍到这,后续还会不断完善中的。