`
yiminghe
  • 浏览: 1433637 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

正则表达式的Javascript应用

阅读更多

网上很好的一篇文章: 正则表达式30分钟入门教程


以及一本经典正则表达式权威 master regular expression

 

其中提到了 很少用到的 零宽断言正则表达式 (Zero-Width Assertions),javascript作为脚本语言虽然没有全部实现,但是对于预测式的零宽断言其实也是实现了的。

 


(?=exp)也叫零宽度正预测先行断言(positive lookahead):

它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。


如:

 

var x=/\b\w+(?=ing\b)/g;
alert("I'm singing while you're dancing.".match(x));

 


(?<=exp)也叫零宽度正回顾后发断言(positive lookbehind 不支持) :

 

 

//not support by javascript from master regular expression
alert("yiminghes book".replace(/(?=s)(?<=yiminghe)/g,"'") == "yiminghe's book");

其实可以用分组回避:

//其实可以用分组捕获来回避的
alert("yiminghes book".replace(/(yiminghe)(?=s)/g,"$1'") == "yiminghe's book");

 

Java 支持 :

 

public class Test {
    public static void main(String[] args){
        //java support lookahead and lookbehind
        System.out.println("yiminghes book".replaceAll("(?=s)(?<=yiminghe)","'") .equals("yiminghe's book"));
       
    }
} 

 

 

 

 

 

 

零宽度负预测先行断言 (?!exp negative lookahead) :

断言此位置的后面不能匹配表达式exp 。例如:\d{3}(?!\d) 匹配三位数字,而且这三位数字的后面不能是数字\b((?!abc)\w)+\b 匹配不包含连续字符串abc的单词


如:

var x=/\b((?!abc)\w)+\b/g;
alert('xyz abc zuc zabc 11'.match(x));

 

也可用来模拟 字符类集合操作 :

 

匹配 a-z 除去 acd

 

alert("z".match(/(?![acd])[a-z]/));

 

举例:匹配页面全部html的例子 (From high performance javascript)

最开始想法:

 

/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>
[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

 

但是当页面html闭合出问题时,由于回朔(backtracking) 性能会不可接受,利用 (?!)可修改为

 

/<html>(?:(?!<head>)[\s\S])*<head>(?:(?!<title>)[\s\S])*<title>
(?:(?!<\/title>)[\s\S])*<\/title>(?:(?!<\/head>)[\s\S])*<\/head>
(?:(?!<body>)[\s\S])*<body>(?:(?!<\/body>)[\s\S])*<\/body>
(?:(?!<\/html>)[\s\S])*<\/html>/

 大大减少了backtracking,但是毕竟?!性能不高,再加上量词*,这个解决方案仍然不是最好,最好的方案见下文原子分组部分。

 

 

 java 直接支持类操作:

 

System.out.println("a".matches("[[a-z]&&[^acd]]"));
 

 


(?<!exp) ,零宽度负回顾后发断言(不支持 negative lookbehind)

 

 

 

零宽度负预测先行断言在javascript中的一个很好的应用例子:

 

 

/**
 * 组合两个正则表达式。 
 * @param[RegExp] r 要组合的一个字符串
 * @param[String] attr attributes of the final new return RegExp
 * @return[RegExp] 
 */
RegExp.prototype.concat = function(r, attr){
 //零宽度负预测先行断言 ,所有捕捉分组个数 ,()不包括	(?:)
 var i=(this.source.match(/\((?!\?:)/g) || "").length; 
 
 //最终的regexp的第二个正则表达式部分的后向引用要考虑本身regexp已有的后向引用,重新编号
 return new RegExp(this.source+r.source.replace(/\\(\d)/g, function($0, $1){
  return "\\" + (i+($1 | 0)); 
 }), attr);
};
 

使用:

 

//匹配2个重复数字后跟一个字母
var x=/(\d)\1(?:\w)/g;
//然后必须紧跟两个重复字母
x=x.concat(/(\w)\1/,'g');
//x == /(\d)\1(?:\w)(\w)\2/g

alert('11aww  22xzy'.match(x));
 

 

原子分组应用 (?>)  不支持 (atomic group)固化分组

 

一旦匹配则消除由当前原子分组内的所有保存状态


保留小数2-3位,如果第三位不为0保留三位,否则保留两位



例子:


0.55555 -> 0.555
0.550005 -> 0.55
0.50002 -> 0.50


可以用正则式

 

"0.625".replace(/(\.\d\d[1-9]?)\d*/,"$1");
 

但是其实 0.625 可以完全不必被匹配(效率问题),于是 [1-9]? 一旦匹配就不要再放弃了,可得


"0.625".replace(/(\.\d\d(?>[1-9]?))\d+/,"$1");

 

但是 js 不支持哦,但是可以用 positive lookhead 结合 backreference 来取代一下。利用 subexpression 来丢失状态以及捕获分组

 

/(\.\d\d(?=([1-9]?))\2)\d+/.test("0.625");

/(\.\d\d(?=([1-9]?))\2)\d+/.test("0.6250981");

 

lookahead 其实就是一个原子分组,但是如前所述它的匹配不消耗字符,因此可以通过将一个lookahead包裹在一个捕捉分组中,并在其后跟上backreference,而形成了以下模式:

 

(?=(pattern to make atomic))\1
 

多个的话只要注意backreference的计数即可。

 

最好的例子:接?!部分的匹配页面html例子:

 

利用原子分组彻底消除回朔可得:

 

/<html>(?=([\s\S]*?<head>))\1(?=([\s\S]*?<title>))\2(?=([\s\S]*?
<\/title>))\3(?=([\s\S]*?<\/head>))\4(?=([\s\S]*?<body>))\5
(?=([\s\S]*?<\/body>))\6[\s\S]*?<\/html>/
 

 

 

 

JAVA 丢失状态例子2 :离开原子分组后 | 保存的状态没了:

 

String str = "^(?>a+|.+)$";
String s = "aaaaaac";
Pattern p = Pattern.compile(str);
Matcher m = p.matcher(s);
System.out.println(m.replaceAll("!"));
 

 

 

 

 

possessive match (+) 不支持

 

同固化分组,一旦匹配就删除用于回朔的保存状态,一般和量词结合

 

"0.625".replace(/(\.\d\d[1-9]?+)\d+/,"$1");
 

js 不支持 ,java.util.regexp 支持

 

System.out.println(".625".matches("(\\.\\d\\d[1-9]?+)\\d+"));

System.out.println(".625".matches("(\\.\\d\\d[1-9]?)\\d+"));
 

DOTALL 模式 (?s) 不支持

 

不支持 java 中的 Pattern.DOTALL 以及 (?s) ,以及 perl 中的 //s ,s modifier  : .可以匹配回车换行


使用alternation以及character class弥补:

 

/.|[\n\r]/.test("\r");
 

条件判断 :(?if then | else) 不支持

 

java ,javascript 均不支持

 

Pattern p = Pattern.compile("(<a>)?<img/>(?(1)\\s*</a>)");
        String s="<img/>";
        Matcher m=p.matcher(s);
        System.out.println(m.group());
 
/(<a>)?<img/>(?(1)\s*</a>)/.test("<img/>");

 

注意 if 中的正则表达式为零宽向前(?=,?!)或向后预测(?<=,><!)正则表达式。如果不写则为零宽正向向前预测。

 

详细解释: 

 

正则表达式 (<a>)?<img/>(?(1)\s*</a>) 相当于: (<a>)?<img/>(?(1)(\s*</a>)|\s*),可匹配的字符串包括 <a><img/></a> 与 <img/>,而不匹配 <a><img/> 或 <img/></a>。


其中 if (1) 为先前匹配到的分组 (<a>),如果先前出现了 <a> 则接着匹配结束标记 </a>,否则直接匹配成功。

 

后果是代码极其不易读,实际中尽量不要使用!可分成多个正则联合检测


\G anchor 不支持

 

还包括 \A,\Z 等锚点都不支持!\G 在 perl,java 中表示当前匹配开始的位置在上次匹配结束的位置,如果失败则不会从字符串的下一个位置重新匹配。

1.在零匹配成功后,\G 位置为当前位置,而下一次匹配位置被强制为当前位置的下一位置(防止死循环),所以\G后只能一次成功零匹配

2.匹配成功后,如果从当前匹配结束位置不能匹配正则,则整体失败,不会从当前匹配结束位置的下一位置进行下一次匹配。


如:

 

       String[] ps = {"x*", "\\Gx*", "ab", "\\Gab","abc","\\Gabc"};
        String s = "abcabc";
        System.out.println(s + " : ");
        for (String str : ps) {
            System.out.print(str + " : ");
            Pattern p = Pattern.compile(str);
            Matcher m = p.matcher(s);
            System.out.println(m.replaceAll("!"));
        }

 

另外命名捕获,正则表达式内模式切换(Pattern.compile("(?i)T(?-i)Est")),注释,unicode 属性区块也不支持。

 

 

? lazy 描述符   支持

 

可修饰 ? 以及 + ,* 等,不加都是贪婪模式,加了则为懒模式了(能不匹配就不匹配):

 

var reg=/.+?/g;
reg.exec("12");
console.log(reg.lastIndex);

var reg=/.??/g;
reg.exec("12");
console.log(reg.lastIndex);

var reg=/.*?/g;
reg.exec("12");
console.log(reg.lastIndex);

 

 

Bonus :

 

String.prototype.replace 的 javascript 实现比较

 

javascript 正则表达式细节问题

 

正则表达式共享问题

 

 

updated 2010-11-24

 

发现一个关于正则式的专业网站 ,详细比较了各种语言的正则引擎,本文内容都已经被他包含.....

 

updated 2011-01-11

 

发现一个很了解各个浏览器正则引擎的blog,原来浏览器也不是完全按照规范来的,各有不同(bug?):


String.split 有问题


non-participate capture group 也有问题

 

 

 

分享到:
评论
2 楼 lmh2072005 2012-12-22  
分析的很好
1 楼 cnlinkin 2009-11-25  
只能期待新的JSengine了~

相关推荐

    JavaScript正则表达式.ppt

    了解正则表达式概念 掌握正则表达式的语法 熟练掌握正则表达式在JavaScript中的应用

    精通正则表达式,有关正则表达式的所有应用

    正则表达式的所有应用都有哦·正则表达式+ASP,正则表达式+JSP,正则表达式+JAVASCRIPT等等

    正则表达式的应用

    介绍了正则表达式的基本概念,以及在VBScript和javascript中如何使用正则表达式,同时,通过一些实例让大家有了感性的认识。正则表达式的应用范围很广,能为大家解决很多实际中的问题。

    正则表达式使用详解及使用实例

    此外,象JavaScript这种客户端的脚本语言也提供了对正则表达式的支持。由此可见,正则表达式已经超出了某种语言或某个系统的局限,成为人们广为接受的概念和功能。  正则表达式可以让用户通过使用一系列的特殊字符...

    神奇的匹配 正则表达式求精之旅

    并基于目前流行的程序语言和应用环境(如C#、ASP.NET、JSP、JavaScript或PHP),全面介绍了创建正则表达式的方法,以及正则表达式在Web环境中的各种应用。 《神奇的匹配:正则表达式求精之旅》适合广大Web网站开发...

    精通正则表达式基于.NET ASP PHP JSP JavaScript

    RegexApplication/Default.aspx 正则表达式类的应用 RegexApplication/GetPageHtmlData.aspx 获取网页的内容 第10章(/10/) ASPNETValidator/Compare.aspx 比较验证 ASPNETValidator/...

    在PHP中使用与Perl兼容的正则表达式

    PHP被大量的应用于Web的后台CGI开发,通常是在用户数据数据之后得出...此外,JavaScript这种客户端的脚本语言也提供了对正则表达式的支持,现在正则表达式已经成为了一个通用的概念和工具,被各类技术人员所广泛使用。

    javaScript正则表达式应用

    javaScript正则表达式应用 javaScript正则表达式应用

    JavaScript 正则表达式高级应用

    JavaScript 正则表达式 里面包含了各种正则表达式规则适合新手学习使用

    php正则表达式

    能应用些基本正则表达式正则表达式是在各种各样语言中突出古怪特征中种但是由于它们看起来是很难个概念 所以很多开发者就把它们放到了角落里忘记了它们存在 让我们先来看看什么是正则表达式为什么你要在PHP中用到...

    经典Javascript正则表达式

    经典Javascript正则表达式 正则表达式用于字符串处理,表单验证等场合,实用高效,但用到时总是不太把握,以致往往要上网查一番。我将一些常用的表达式收藏在这里,作备忘之用。  匹配中文字符的正则表达式:  [\...

    正则表达式测试器。exe

    正则表达式测试器是程序...不管您是PHP还是.NET程序员,不管您正在做窗口应用开发,还是采用JAVASCRIPT进行WEB开发,正则表达式都能助您一臂之力。软件还提供了常用的正则表达式库供随时调用参考。本软件为免费软件。

    C# 最全的日期正则表达式,没有之一

    考虑到这个正则表达式仅仅是用作验证,所以捕获组没有意义,只会占用资源,影响匹配效率,所以可以使用非捕获组来进行优化。 ^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2...

    正则表达式,javascript

    正则表达式全解,就很好的学习正则表达式在JAVASCRIPT中的应用的教程

    PHP正则表达式基本语法和使用方法

    正则表达式(regular expression)是一种表示方式,最早在LINUX被当做一种搜索算法应用在编辑器中,后来被广泛应用,不仅PHP脚本支持正则表达式,Perl、C#、Java以及JavaScript和MySQL也对正则表达式支持。...

    常用的JavaScript验证正则表达式应用规则

    要匹配“toon”,使用“tn”正则表达式。这里不能使用方扩号,因为方括号只答应匹配单个字符;这里必须使用圆括号“”。圆括号还可以用来分组,具体请参见后面介绍。1.4表示匹配次数的符号表一显示了表示匹配次数的...

    精通正则表达式(第3版) Mastering.Regular.Expressions

     第3 版在前面的章节中增加了PHP的相关内容,并专门为理解和应用PHP的正则表达式增加了一章全新的内容。另外,该版对Java的章节也进行了修订,做了可观的扩充,反映了Java1.5和Java1.6的新特性。  

    正则表达式

    我们已经发现了,在正则表达式中所有的字母字符和数字都是按照字面意思与自身相匹配的.JavaScript的正则表达式还通过以反斜杠(\)开头的转义序列支持某些非 字母字符.例如,序列 "\n" 在字符串中匹配的是一个直接量换...

    正则表达式测试器 1.0┊方便地进行正则表达式的匹配测试┊简体中文绿色免费版

    正则表达式测试器是程序...不管您是PHP还是.NET程序员,不管您正在做窗口应用开发,还是采用JAVASCRIPT进行WEB开发,正则表达式都能助您一臂之力。软件还提供了常用的正则表达式库供随时调用参考。本软件为免费软件。

    正则表达式的使用

    正则表达式在很多语言中都会用到,其内容几乎是独立于具体语言,因此,本章与其他章节联系不是很大。但这并不意味着正则表达式的用处不大。事实上,正则表达式有着非常...本章主要介绍正则表达式在JavaScript中的应用。

Global site tag (gtag.js) - Google Analytics