创建正则表达式
- 字面直接量
// /pattern/flags
/* flags(组合):
1. m(multiple)多行匹配
2. i(ignore) 忽略大小写
3. g(global) 全局匹配
*/
var regx = /ab+c/g;
- RegExp对象
// new RegExp('pattern','flags')
// flags 同上
var regx = new RegExp("ab+c");
var regex = new RegExp(/^[a-zA-Z]+[0-9]*\W?_$, "gi");
两种创建方式的区别:
-
字面直接量:在加载脚本后,正则表达式字面值提供正则表达式的编译。当正则表达式保持不变时,使用此方法可获得更好的性能。
-
构造函数: 使用构造函数提供正则表达式的运行时编译。使用构造函数,当你知道正则表达式模式将会改变,或者你不知道模式,并从另一个来源,如用户输入。
RegExp的三大方法
- test
检测指定字符串是否含有某个子串(或者匹配模式),返回true或者false。
var s = 'you love me and I love you';
var pattern = /you/;
var ans = pattern.test(s);
console.log(ans); // true
- exec
提取指定字符串中的符合要求的子串(或者匹配模式),返回一个数组存放匹配结果;如果没有,则返回null。(也可自己写方法循环提取所有或者指定index的数据)
exec可以说是test的升级版本,因为它不仅可以检测,而且检测到了可以直接提取结果。
var rex = new RegExp("d(b+)d", "g");
var arr = rex.exec("cdbbdbsbz");
rex和arr的说明:
对象 |
属性或索引 |
描述 |
在例子中对应的值 |
arr |
|
匹配到的字符串和所有被记住的子字符串。 |
["dbbd","bb"] |
arr |
index |
在输入的字符串中匹配到的以0开始的索引值。 |
1 |
arr |
input |
初始字符串。 |
"cdbbdbsbz" |
arr |
[0] |
匹配到的所有字符串 |
"dbbd" |
rex |
lastIndex |
下一个匹配的索引值。 |
5 |
rex |
source |
模式文本。在正则表达式创建时更新,不执行. |
"d(b+)d" |
当正则表达式带有全局标志g时,exec则永远返回第一个匹配项。但是当连续调用exec时,则每次的返回值都是下一个匹配项。
- compile
改变当前匹配模式(pattern)
String对象正则相关的方法(4大护法)
- search 方法
搜索指定字符串中是否含有某子串(或者匹配模式),如有,返回子串在原串中的初始位置,如没有,返回-1。
是不是和test类似呢?test只能判断有木有,search还能返回位置!当然test()如果有需要能继续找下去,而search则会自动忽略g(如果有的话)。
var s = 'you love me and I love you';
var pattern = /you/;
var ans = s.search(pattern);
console.log(ans); // 0
话说和String的indexOf方法有点相似,不同的是indexOf方法可以从指定位置开始查找,但是不支持正则。
- match 方法
和exec类似,从指定字符串中查找子串或者匹配模式,找到返回数组,没找到返回null
match是exec的轻量版,当不使用全局模式匹配时,match和exec返回结果一致;当使用全局模式匹配时,match直接返回一个字符串数组,获得的信息远没有exec多,但是使用方式简单。
var s = 'you love me and I love you';
console.log(s.match(/you/)); // ["you", index: 0, input: "you love me and I love you"]
console.log(s.match(/you/g)); // ["you", "you"]
- repleace 方法
用另一个子串替换指定字符串中的某子串(或者匹配模式),返回替换后的新的字符串 str.replace(‘搜索模式’,'替换的内容’) 如果用的是pattern并且带g,则全部替换;否则替换第一处。
var s = 'you love me and I love you';
console.log(s.replace('you', 'zichi')); // zichi love me and I love you
console.log(s.replace(/you/, 'zichi')); // zichi love me and I love you
console.log(s.replace(/you/g, 'zichi')); // zichi love me and I love zichi
如果需要替代的内容不是指定的字符串,而是跟匹配模式或者原字符串有关,那么就要用到$了(记住这些和$符号有关的东东只和replace有关哦)。
字符 |
替换文本 |
$1、$2、...、$99 |
与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。 |
$& |
与 regexp 相匹配的子串。 |
$` |
位于匹配子串左侧的文本。 |
$' |
位于匹配子串右侧的文本。 |
$$ |
直接量符号。 |
var s = 'I love you';
var pattern = /love/;
var ans = s.replace(pattern, '$`' + '$&' + "$'");
console.log(ans); // I I love you you
没错,’$`’ + ‘$&’ + “$’”其实就相当于原串了!
//交换 Doe,John ->> John,Doe
var name = "Doe, John";
name.replace(/(\w+)\s*, \s*(\w+)/, "$2 $1");//John,Doe
//首字母大写
name = 'aaa bbb ccc';
uw=name.replace(/\b\w+\b/g, function(word){
return word.substring(0,1).toUpperCase()+word.substring(1);}
);
replace,替换字符串可以是function
"<%= name %><%- aaa%><%ccc%>".replace(/<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$/g,function(){
console.log(arguments);
});
/<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$/g.exec("<%= name %><%- aaa%><%ccc%>");
//每次function接收的参数和执行exec的方法的内容一样,但是有点区别
//执行exec返回的是一个数组,[匹配到的字符串,子表达式匹配到的字符串1,子表达式2匹配的到字符串,....,子表示n匹配的字符串],属性包括,input 元字符串,index 匹配到的字符串的起始索引
比较图片:
![image](https://camo.githubusercontent.com/d7bd5a388e31bde2c98edb04c6814440afc41952c5a6fc6db3124689a31ede42/687474703a2f2f6e6f74652e796f7564616f2e636f6d2f7977732f6170692f706572736f6e616c2f66696c652f57454266333333353932613261383161363765343037366138393934623436666530383f6d6574686f643d646f776e6c6f61642673686172654b65793d3562393337333336326566316466343538323462333534343761396535313663)
![image](https://camo.githubusercontent.com/554c9afb7510066a1c17ef0ef721d15ded196b8ff3e28780fee5b984e85d2553/687474703a2f2f6e6f74652e796f7564616f2e636f6d2f7977732f6170692f706572736f6e616c2f66696c652f57454232333132626164653331313166353831636635616466306532666538346336323f6d6574686f643d646f776e6c6f61642673686172654b65793d3565643466636363333665366266356432613137646362323039356235313662)
- split 方法
字符串分割成字符串数组的方法(另有数组变成字符串的join方法)。
直接看以下例子:
var s = 'you love me and I love you';
var pattern = 'and';
var ans = s.split(pattern);
console.log(ans); // ["you love me ", " I love you"]
match 和 exec的区别
相同点
- 两个方法都是查找符合条件的匹配项,并以数组形式返回。
- 当没有找到匹配项时,都返回null。
- 当正则表达式包含子表达式且不包含全局标志g时,二者返回相同的数组。
示例:
var str = 'cat10,bat20,kat30';
var patten = /\w(at)\d+/;
var arr = str.match(patten);
arr[0] <=> ['cat10']
arr[1] <=> ['at']
var arr = patten.exec(str);
arr[0] <=> ['cat10']
arr[1] <=> ['at']
不同点:
- match是字符串的方法,exec是RegExp对象的方法
- 当正则表达式带有全局标志g时,二者表现不一致。
match会返回所有符合条件的匹配项,并以数组形式返回。数组第一项存放第一个匹配项,数组第二项存放第二个匹配项...依次类推。
exec则永远返回第一个匹配项。但是当连续调用exec时,则每次的返回值都是下一个匹配项。
//示例1:
var str = 'cat,bat,kat';
var patten = /at/g;
str.match(patten); //['at', 'at', 'at']
patten.exec(str); //['at']
//示例2:
var str = 'cat,bat,kat';
var patten = /\w+/g;
str.match(patten); //['cat', 'bat', 'kat']
//第一次调用
patten.exec(str); //['cat']
//第二次调用
patten.exec(str); //['bat']
//第三次调用
patten.exec(str); //['kat']
- 当正则表达式包含子表达式时且包含全局标志g时,二者表现不一致。
match会返回所有符合条件的匹配项,并以数组形式返回。这时,match不会再返回子表达式的匹配项了。数组第一项存放第一个匹配项,数组第二项存放第二个匹配项...依次类推。
exec会返回子表达式的匹配项。换句话说就是,数组第一项存放整个匹配项,数组第二项存放第一个子表达式匹配项,数组第三项存放第二个子表达式匹配项...依次类推。
示例:
var str = 'cat10,bat20,kat30';
var patten = /\w(at)\d+/g;
var arr = str.match(patten); //['cat10', 'bat20', 'kat30']
var arr = patten.exec(str);
arr[0] <=> ['cat10']
arr[1] <=> ['at']
零宽断言
零宽断言(zero-length assertions)这概念直译过于术语化。零宽的意思是指该位置是不占宽度的,也就是只作断言判断,但不匹配实际的内容,比如\d(?=.)这个正向先行断言(这概念也归纳在后)就只匹配点号之前的数字,但是它并不会匹配到这个点号,这个\d(?=.)括号中的匹配内容也就是零宽了。
贪婪模式和非贪婪模式
String str="abcaxc";
Patter p="ab*c";
-
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab*c)。
-
非贪婪匹配:就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab*c)。
贪婪量词,惰性量词,支配性量词
- 贪婪量词
所有简单量词。就像成语中说的巴蛇吞象那样,一口吞下整个字符串,发现吞不下(匹配不了),再从后面一点点吐出来(去掉最后一个字符,再看这时这个整个字符串是否匹配,不断这样重复直到长度为零)
- 惰性量词
隋性量词,在简单量词后加问号。由于太懒了,先吃了前面第一个字符,如果不饱再捏起多添加一个(发现不匹配,就读下第二个,与最初的组成一个有两个字符串的字符串再尝试匹配,如果再不匹配,再吃一个组成拥有三个字符的字符串……)。其工作方式与贪婪量词相反。
- 支配性量词
支配性量词,在简单量词后加加号。上面两种都有个不断尝试的过程,而支配性量词却只尝试一次,不合口味就算了。就像一个出身高贵居支配地位的公主。但你也可以说它是最懒量词。由于javascript不支持,所以它连出场的机会也没有了。
构建一个模板工具
// underscore代码
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate: /<%([\s\S]+?)%>/g,
interpolate: /<%=([\s\S]+?)%>/g,
escape: /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',//
'\r': 'r',//回车
'\n': 'n',//换行
'\u2028': 'u2028',//行分隔符
'\u2029': 'u2029'//段落分隔符
};
var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
var escapeChar = function(match) {
return '\\' + escapes[match];
};
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
// NB: `oldSettings` only exists for backwards compatibility.
_.template = function(text, settings, oldSettings) {
if (!settings && oldSettings) settings = oldSettings;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
// 匹配的组
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
//replace function args
source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
index = offset + match.length;
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
} else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
} else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
// Adobe VMs need the match returned to produce the correct offset.
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + 'return __p;\n';
var render;
try {
render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled source as a convenience for precompilation.
var argument = settings.variable || 'obj';
template.source = 'function(' + argument + '){\n' + source + '}';
return template;
};
正则表达式的思维导图
![image](https://camo.githubusercontent.com/42e12ce60454d9d7901fc159700d0f0a347fc41ad58af0d831cf4172deaa0cae/687474703a2f2f6e6f74652e796f7564616f2e636f6d2f7977732f6170692f706572736f6e616c2f66696c652f57454266633337623461393238323864343538666338373832666131383763376665633f6d6574686f643d646f776e6c6f61642673686172654b65793d3361343266623365616166373637396135376564346562333434343239376134)
正则表达式在线工具
http://tool.oschina.net/regex
参考文章:
- http://www.cnblogs.com/rubylouvre/archive/2010/03/09/1681222.html
- http://www.cnblogs.com/tinkbell/p/4563688.html
- https://segmentfault.com/a/1190000004106110
- http://www.codeceo.com/article/javascript-reg-expression.html
- http://www.cnblogs.com/dojo-lzz/p/5518474.html