`
yiminghe
  • 浏览: 1460361 次
  • 性别: 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了~

相关推荐

    正则表达式必知必会v_1.0.pdf

    正则表达式是一种强大的文本处理工具,广泛应用于各个领域。下面是对正则表达式的详细解释: 正则表达式的用途 正则表达式主要用于处理文本,提供了两大主要功能:查找和替换。查找功能允许用户根据不同的规则来...

    正则表达式的应用全集

    10. **JavaScript中的正则**:在《JS正则表达式 .txt》中,讲解了JavaScript语言中如何使用正则表达式,包括`test()`、`match()`、`replace()`等方法。 11. **深入理解正则表达式**:《深入浅出之正则表达式.txt》...

    精通正则表达式(第三版)简体中文版

    - **JavaScript中的正则表达式**:JavaScript的正则表达式对象提供了丰富的功能,包括全局匹配、忽略大小写等选项。 - **.NET框架中的正则表达式**:通过System.Text.RegularExpressions命名空间提供支持。 #### 六...

    javascript正则表达式迷你书 (1).pdf

    本书是 JavaScript 正则表达式的入门级教程,旨在帮助读者快速掌握正则表达式的基本概念和应用。下面是本书的知识点摘要: 第一章:正则表达式字符匹配攻略 * 两种模糊匹配:横向模糊匹配和纵向模糊匹配 * 字符组...

    常用正则表达式大全.txt

    根据提供的文件信息,我们可以整理出一系列与正则表达式相关的...以上内容概括了从文件中提取出来的正则表达式知识点,这些知识点覆盖了正则表达式的多个应用场景,对于从事软件开发、数据分析等领域的人来说非常实用。

    正则表达式的高级应用

    在JavaScript中,正则表达式主要通过`RegExp`对象实现,可以使用构造函数`new RegExp()`或者正则表达式直接量(以`/`包围)来创建。 1. **JavaScript中的正则表达式** - **创建正则表达式**:你可以使用 `/pattern...

    只验证数字和字母的正则表达式

    ### 正则表达式的应用与理解 在计算机编程与数据处理领域中,正则表达式是一种非常强大的文本匹配工具。本文将围绕一个特定的正则表达式 `/^([A-Za-z0-9])+$/` 展开讨论,该表达式主要用于验证输入字符串是否仅包含...

    使用正则表达式验证一年的12个月份

    正则表达式是一种强大的文本处理工具,用于匹配、查找、替换等操作,广泛应用于编程语言中。在IT行业中,正则表达式是处理字符串时不可或缺的一部分,尤其在数据验证、文本提取等方面。在这个场景中,我们需要创建一...

    正则表达式调试工具

    正则表达式(Regular Expression,简称regex)是用于在文本中匹配特定模式的强大工具,广泛应用于数据验证、搜索替换和文本处理等领域。正则表达式调试工具是开发人员用来测试和优化这些模式的重要辅助工具。本文将...

    源码(精通正则表达式&实战正则表达式)

    本资源“源码(精通正则表达式&实战正则表达式)”专注于JavaScript环境下的正则表达式学习,通过一系列视频教程和配套源码,帮助开发者提升对正则表达式的理解和应用能力。 首先,"精通正则表达式五部视频"可能涵盖...

    通过正则表达式生成数据

    2. **利用编程语言**:大多数编程语言如Python、Java、JavaScript等都内置了正则表达式的支持,并提供了方法来生成符合正则表达式的随机字符串。例如,Python的`re`模块配合`random.choice`或`random.choices`可以...

    JavaScript正则表达式.ppt

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

    精通正则表达式中文版英文版_中文版为扫描版

    书中的例子涵盖了多种编程语言,如Perl、Java、JavaScript、.NET等,这些语言的正则表达式引擎虽然大同小异,但在细节上有所区别,学习者将了解到如何在不同环境下应用正则表达式。 对于初学者,书中会引导他们理解...

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

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

    正则表达式(日期校验)

    ### 正则表达式在日期校验中的应用 #### 一、引言 在软件开发过程中,日期格式的校验是非常常见的需求之一。利用正则表达式进行日期格式的校验,不仅可以提高代码的可读性和简洁性,还能有效地确保输入数据的准确...

    正则表达式学习手册

    正则表达式的应用场景非常广泛,尤其在编程领域中不可或缺。对于初学者来说,掌握正则表达式的基础知识尤为重要。 #### 2. 正则表达式基础规则 ##### 2.1 普通字符 - **定义**:普通字符包括但不限于字母、数字、...

    正则表达式判断密码强度

    在Web应用开发中,例如"WebApplication2"这样的项目,可以利用前端验证(如JavaScript)和后端验证(如服务器端语言如Java、Python等)双重校验密码强度,以提供更高的安全性。前端验证可以即时反馈给用户,而后端...

    JS正则表达式大全 (正则表达式用于简化js中的代码)

    正则表达式是一种在文本中查找或替换字符串的强大工具,在JavaScript中被广泛应用于数据验证、字符串搜索与替换等场景。通过学习并掌握正则表达式的使用方法,可以极大地提高编程效率。 #### 二、基本语法 ##### 1...

Global site tag (gtag.js) - Google Analytics