我想正则表达式之所以难,主要体现在以下几个方面: 1)正则表达式的符号晦涩难懂
2)不支持排版(至少 javascript 目前还不支持)
3)不能设置断点,不能跟踪调试
4)没有真正的标准,不同工具所支持的正则表达式有许多细节上的差异
下文中如涉及正则表达式符号含义不明,请参阅《javascript 正则表达式入门笔记(完整版)》
正则表达式本质上是一整套的处理字符串的模型,帮助人们利用简短的表达式来实现复杂的算法。早期的正则表达式引擎只有三百多行代码,发展到后来也不到 1 万 行代码。打一个不恰当的比喻,利用正则表达式处理字符串,就像是利用 SQL 处理数据。正如我们在处理数据时要避免使用复杂 SQL,我们在处理字符串时也应 当避免使用复杂的正则表达式。下面是一段判断 IP 地址合法性的代码,比单纯用正则表达式要简单:
var isIPAdress = function(IPStr){
var pttrn = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
var IPObj = pttrn.exec(IPStr);
var bool_result = false;
if(IPObj){
// 添加进一步的识别规则
if(IPStr==="0.0.0.0"){
bool_result = false;
}else if(IPStr==="1.1.1.1"){
bool_result = false;
}else if(IPObj[1]>=0 && IPObj[1]<=255 && IPObj[2]>=0 && IPObj[2]<=255 && IPObj[3]>=0 && IPObj[3]<=255 && IPObj[4]>=0 && IPObj[4]<=255){
bool_result = true;
}else{
bool_result = false;
}
}
return bool_result;
}
调试信息:
isIPAdress("10.1.6.255") true
isIPAdress("1.1.1.1") false
isIPAdress("10.1.a.255") false
浅议正则表达式的执行效率
执行下面这个 javascript 的正则表达式,比较 ie/safari/firefox/chrome 的执行效率,发现 safari 和 firefox 首 次打开时较慢但是再刷新可做到瞬间完成,chrome 和 ie 则是每次打开和刷新都慢,这说明 javascript 在 ie 和 chrome 上还是完全基于 NFA 算法做优化,safari 和 firefox 则可能用到了 DFA 算法(也可能是缓存)。
var p1 = /X(?:.+)+X/;
iJs.put(p1.exec("=XX=========================="));
正则表达式对象:exec 方法:
如果正则表达式使用了 g 作为后缀,则会记住上次执行的结果,执行时会找后面匹配。
如果正则表达式没有使用 g 作为后缀,则每次执行的结果相同,都是取第一个匹配上的。如果使用了捕获型括号,则匹配结果可通过 1 /2/3/… 后缀获得,参见前面给出的判断 IP 地址合法性的代码。
var pttrn = /bb/;
iJs.showObject(pttrn.exec("abaabbaaa"));
iJs.showObject(pttrn.exec("abaabbaaa"));
pttrn = /a+/g;
iJs.showObject(pttrn.exec("abaabbaaa"));
iJs.showObject(pttrn.exec("abaabbaaa"));
调试信息:
[Object] bb
|–[string] 0 ————- bb
|–[number] index ————- 4
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 6
[Object] bb
|–[string] 0 ————- bb
|–[number] index ————- 4
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 6
[Object] a
|–[string] 0 ————- a
|–[number] index ————- 0
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 1
[Object] aa
|–[string] 0 ————- aa
|–[number] index ————- 2
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 4
正则表达式对象:test 方法
返回 true 或 false
var pttrn = /bb/;
iJs.pt('pttrn.test("abaabbaaa")');
iJs.pt('pttrn.test("ababab")');
调试信息:
pttrn.test("abaabbaaa") true
pttrn.test("ababab") false
字符串对象:match 方法
match 方法返回一个对象,需注意如果正则表达式使用了后缀 g,则捕获型括号会失效。
var pttrn = /a(b)+/;
var pttrn_g = /a(b)+/g;
var myStr = "abaabbaaa";
var matchObj = myStr.match(pttrn);// 捕获 b
var matchObj_g = myStr.match(pttrn_g);// 捕获失效
iJs.pt("pttrn");
iJs.pt("pttrn_g");
iJs.pt("myStr");
iJs.showObject("matchObj");
iJs.showObject("matchObj_g");
调试信息:
pttrn /a(b)+/
pttrn_g /a(b)+/g
myStr abaabbaaa
[Object] matchObj
|–[string] 0 ————- ab
|–[string] 1 ————- b
|–[number] index ————- 0
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 2
[Object] matchObj_g
|–[string] 0 ————- ab
|–[string] 1 ————- abb
|–[number] index ————- 3
|–[string] input ————- abaabbaaa
|–[number] lastIndex ————- 6
字符串对象:replace 方法
如果 replace 第一个参数输入的是字符串或不带后缀的正则表达式,则只匹配替换一次。
只有正则表达是带后缀 g 才能替换全部。
第二个参数可以是函数,下面的例子中打印了函数接受的参数结构。第一个参数是匹配字符串、第二个参数开始是捕获字符串、然后跟着 index、最后是字符串自己。
var myStr = "abaabbaaabbb";
var searchValue = "a";
var searchRegExp = /a+/;
var searchRegExp_g = /a+/g;
var replaceValue = "X";
iJs.pt("myStr");
iJs.pt("searchValue");
iJs.pt("replaceValue");
iJs.pt("myStr.replace(searchValue,replaceValue)");
iJs.put("");
iJs.pt("myStr");
iJs.pt("searchRegExp");
iJs.pt("replaceValue");
iJs.pt("myStr.replace(searchRegExp,replaceValue)");
iJs.put("");
iJs.pt("myStr");
iJs.pt("searchRegExp_g");
iJs.pt("replaceValue");
iJs.pt("myStr.replace(searchRegExp_g,replaceValue)");
iJs.put("");
var myStr_f = "a2aa22aaa222________";
var searchRegExp_g2 = /(a+)2/g;
var args;// 全局变量便于 iJs1 捕获对象
var replaceFunction = function(a,b){
var slice = Array.prototype.slice;
args = slice.apply(arguments);
iJs1.showObject("args");
return args[0]+"+";
};
iJs.pt("myStr_f.replace(searchRegExp_g2,replaceFunction)");
调试信息:
myStr abaabbaaabbb
searchValue a
replaceValue X
myStr.replace(searchValue,replaceValue) Xbaabbaaabbb
myStr abaabbaaabbb
searchRegExp /a+/
replaceValue X
myStr.replace(searchRegExp,replaceValue) Xbaabbaaabbb
myStr abaabbaaabbb
searchRegExp_g /a+/g
replaceValue X
myStr.replace(searchRegExp_g,replaceValue) XbXbbXbbb
myStr_f.replace(searchRegExp_g2,replaceFunction) a2+aa2+2aaa2+22________
补充调试信息:
[Object] args
|–[string] 0 ————- a2
|–[string] 1 ————- a
|–[number] 2 ————- 0
|–[string] 3 ————- a2aa22aaa222________
[Object] args
|–[string] 0 ————- aa2
|–[string] 1 ————- aa
|–[number] 2 ————- 2
|–[string] 3 ————- a2aa22aaa222________
[Object] args
|–[string] 0 ————- aaa2
|–[string] 1 ————- aaa
|–[number] 2 ————- 6
|–[string] 3 ————- a2aa22aaa222________
字符串对象:search 方法
search 方法和 indexOf 方法类似,但是接受的是正则表达式对象,如果能够匹配,则返回首次匹配的首字符位置,如果不能匹配,则返回 -1。此方法会忽略 g 标志。
var myStr = "abaabbaaabbb";
var searchRegExp1 = /aaa/;
iJs.pt("myStr.search(searchRegExp1)");
var searchRegExp2 = /aXa/;
iJs.pt("myStr.search(searchRegExp2)");
调试信息:
myStr.search(searchRegExp1) 6
myStr.search(searchRegExp2) -1