JavaScript中正则表达式的使用

Quick reference

regex.jpg

创建正则对象

两种创建方法:

  1. 使用RegExp 构造函数

    var re1 = new RegExp("abc");
    var re2 = new RegExp("abc",'i'); //大小写不敏感
    

    第二个参数为修饰符,可以指定匹配是否为全局匹配,是否为大小写敏感等。

  2. 直接将表达式包括在正斜杠里面

var re2 = /abc/i;
var re3 = /[\d.+]/;
> 特殊字符当做普通字符用,比如问号和加号,需用 \ 转义;
> 方括号里面的特殊字符如 `.` 和 `+` 没有特殊含义,当作普通字符用。

实际应用中,基本上都采用第二种的写法,更加便捷。

正则对象的属性

与表达式相关的属性:

  • flags:返回一个字符串,表示使用到的修饰符,按字母顺序排列。
  • global:返回一个布尔值,表示是否设置了g修饰符,该属性只读。
  • ignoreCase:返回一个布尔值,表示是否设置了i修饰符,该属性只读。
  • multiline:返回一个布尔值,表示是否设置了m修饰符,该属性只读。
  • source:返回正则表达式的字符串形式(不包括反斜杠),该属性只读。
/foo/ig.flags;   // "gi"
/bar/myu.flags;  // "muy"
/foo/ig.global;  // true
/foo/ig.ignoreCase;  // true
/bar/myu.multiline;  // true
/bar/myu.source;     //"bar"

lastIndex属性:

返回下一次开始搜索的位置。该属性可读写,但是只在设置了g修饰符时有意义。

正则对象的方法

test()

返回一个布尔值,没有匹配项,返回false;有匹配项,返回true。

console.log(/abc/.test("abcde")); //true
console.log(/[0-9]/.test("in 1992"));//true
console.log(/'\d*'/.test("'123'")); //true
console.log(/neighbou?r/.test("neighbor")); //ture
console.log(/\bcat\b/.test("concatenate")); //false

使用全局匹配的时候,即表达式里面使用了g作为修饰符,每次使用test,下一次的开始匹配位置是上一次匹配成功的位置。

var digit = /\d/g;
var str = "x_1_x_0";
digit.test(str);    // true
digit.lastIndex;    // 3
digit.test(str);    // true
digit.lastIndex;    // 7
digit.test(str);    // false
digit.lastIndex;    // 0

使用lastIndex可以控制匹配的开始位置。

var pattern = /y/g;     //必须全局匹配
pattern.lastIndex = 3;  //指定匹配开始的位置
console.log(pattern.test("zzy")); //false

exec()

返回匹配的结果。没有匹配项,返回null;有匹配项,返回一个数组。

var match = /\d+/.exec("one two 100"); 
console.log(match);         // [ '100', index: 8, input: 'one two 100' ]
console.log(match.index);   // 8

如果表达式中有圆括号,即一个group,与group匹配的内容也能返回:

console.log(/_(x)/.exec("_y_x")); 
// [ '_x', 'x', index: 2, input: '_y_x' ]
console.log(/bad(ly)?/.exec("bad")); 
// [ 'bad', undefined, index: 0, input: 'bad' ] 没有匹配到的group返回undefined
console.log(/(\d)+/.exec("123"));    
//[ '123', '3', index: 0, input: '123' ] 匹配到多次,返回最后一次的

数组里面有两个属性:

  1. input:整个原字符串。
  2. index:整个模式匹配成功的开始位置(从0开始计数)。

使用全局匹配的时候,下一次的开始匹配位置是上一次匹配成功的位置。可以用这个特点进行遍历,找出所有的匹配项。

var input = "A string with 3 numbers in it... 42 and 88.";
var number = /\b(\d+)\b/g;
var match;
while (match = number.exec(input))
    console.log("Found", match[1], "at", match.index);
// Found 3 at 14
// Found 42 at 33
// Found 88 at 40

字符串对象中使用正则表达式

有四种方法可以使用正则表达式:

replace():按照给定的表达式替换字符串,返回替换后的字符串。

match():返回一个数组,成员是所有匹配的子字符串。

search():按照给定的表达式搜索字符串,返回一个整数,表示匹配到的位置。

split():按照给定的表达式分割字符串,返回一个数组,包含分割后的各个成员。

replace()

该方法的第一个参数是表达式,第二个参数是要替换的内容。

console.log("papa".replace("p", "m")); //mapa 第一个匹配上的被替换
console.log("Borobudur".replace(/[ou]/, "a")); // Barobudur
console.log("Borobudur".replace(/[ou]/g, "a")); //Barabadar

replace真正的厉害之处在于,它的第二个参数可以使用$指代匹配到的内容:

  • $& 指代匹配到的字符串。
  • $` 指代匹配结果前面的文本。
  • $' 指代匹配结果后面的文本。
  • $n 指代匹配成功的第n组内容,n是从1开始的自然数。
  • $$ 指代美元符号$
console.log("Hopper Grace".replace(/(\w+)\s(\w+)/g, "$&-->$2 $1")); 
//Hopper Grace-->Grace Hopper
console.log('abc'.replace('b', '[$`-$&-$\']'));
// "a[a-b-c]c"

replace的第二个参数也可以是function

var s = "the cia and fbi";
console.log(s.replace(/\b(fbi|cia)\b/g, function(str) {
  return str.toUpperCase();
}));    //the CIA and FBI

match

exec()方法类似,匹配成功返回一个数组,失败返回null

全局匹配的时候,一次性返回所有匹配的项。

console.log("one two 100".match(/\d+/));//["100"]
console.log("Banana".match(/an/g));     //["an", "an"]

search()

返回第一个匹配项的位置,没有任何匹配的项,返回-1。

console.log(" word".search(/\S/));  //2
console.log(" ".search(/\S/));      //-1

split()

使用字符分割

var temp = 'Oh brave new world that has such people in it.';
temp.split(' ');
// ['Oh', 'brave', 'new', 'world', 'that', 'has', 'such', 'people', 'in', 'it.']

使用正则表达式分割

// 使用分号分割,并将其前后的空格去除
var names = 'Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ;Chris Hand ';

var re = /\s*;\s*/;
var nameList = names.split(re);

console.log(nameList);
// [ 'Harry Trump','Fred Barney','Helen Rigby','Bill Abel','Chris Hand '];
// 试试看,如果正则表达式为 /(\s*;\s*)/ ,会返回什么呢?

使用正则表达式分割,并返回匹配到的内容

var myString = 'Hello 1 word. Sentence number 2.';
var splits = myString.split(/(\d)/);

console.log(splits);
//[ "Hello ", "1", " word. Sentence number ", "2", "." ]

返回指定长度的数组

var myString = 'Hello World. How are you doing?';
var splits = myString.split(' ', 3);

console.log(splits);
// ["Hello", "World.", "How"]

可以用它实现字符串的反转

var str = 'asdfghjkl';
var strReverse = str.split('').reverse().join(''); 
// 'lkjhgfdsa'
// 可以用来测试字符串是否为回文

RegExp对象

var name = "harry";
var text = "Harry is a suspicious character."; 
    //在名字下面加下划线
var regexp = new RegExp("\\b(" + name + ")\\b", "gi"); 
console.log(text.replace(regexp, "_$1_"));  
    // _Harry_ is a suspicious character.

匹配机制

var animalCount = /\b\d+ (pig|cow|chicken)s?\b/;
console.log(animalCount.test("15 pigs"));       // true
console.log(animalCount.test("15 pigchickens"));// false
Paste_Image.png
var number = /\b([01]+b|\d+|[\da-f]+h)\b/;
//十进制/二进制/十六进制数
Paste_Image.png

贪婪匹配

先看一个例子,它的作用是将JavaScript代码中的注释去掉:

function stripComments(code){
    return code.replace(/\/\/.*|\/\*[^]*\*\//g, "");
}
console.log(stripComments("1 + /* 2 */3"));   // 1 + 3
console.log(stripComments("X = 10;// ten!")); // X = 10;
console.log(stripComments("1 /* a */+/* b */ 1")); // 1 1 有问题

//.*表示单行注释,/*[^]*\*/表示多行注释。其中/和最后一个*做普通字符用,所以用\来转义。
第一个表达式用 . 表示任意字符;第二个用 [^] 表示任意字符,因为多行注释会有换行。

最后一个有问题是贪婪匹配,即尽可能地匹配多个字符。在它后面加上问号,它就尽可能少地匹配,即 [^]*? 。同样也适用于+,?,{}。

function stripComments(code) {
    return code.replace(/\/\/.*|\/\*[^]*?\*\//g, "");
}
console.log(stripComments("1 /* a */+/* b */ 1")); //1 + 1

在线工具

正则表达式在线测试:https://www.debuggex.com

参考:

Eloquent JavaScript Chapter9
阮一峰 RegExp对象
Mozilla Developer Network

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容