关于正则表达式匹配时间的问题 为什么下面这段正则表达式匹配时间无法匹配 这一段文字?

做日志分析工作的经常需要跟成千上万的日志条目打交道,为了在庞大的数据量中找到特定模式的数据,常常需要编写很多复杂的正则表达式。例如枚举出日志文件中不包含某个特定字符串的条目,找出不以某个特定字符串打头的条目,等等。
使用否定式前瞻
正则表达式中有前瞻(Lookahead)和后顾(Lookbehind)的概念,这两个术语非常形象的描述了正则引擎的匹配行为。需要注意一点,正则表达式中的前和后和我们一般理解的前后有点不同。一段文本,我们一般习惯把文本开头的方向称作“前面”,文本末尾方向称为“后面”。但是对于正则表达式引擎来说,因为它是从文本头部向尾部开始解析的(可以通过正则选项控制解析方向),因此对于文本尾部方向,称为“前”,因为这个时候,正则引擎还没走到那块,而对文本头部方向,则称为“后”,因为正则引擎已经走过了那一块地方。如下图所示:
所谓的前瞻就是在正则表达式匹配到某个字符的时候,往“尚未解析过的文本”预先看一下,看是不是符合/不符合匹配模式,而后顾,就是在正则引擎已经匹配过的文本看看是不是符合/不符合匹配模式。符合和不符合特定匹配模式我们又称为肯定式匹配和否定式匹配。
现代高级正则表达式引擎一般都支持都支持前瞻,对于后顾支持并不是很广泛,因此我们这里采用否定式前瞻来实现我们的需求。
测试数据:
04:38:44 127.0.0.1 GET /robots.txt
04:38:44 127.0.0.1 GET /posts/robotfile.txt
04:38:44 127.0.0.1 GET /
例如上面这几条简单的日志条目,我们想实现两个目标:
1. 把8号的数据过滤掉 2. 把那些不包含robots.txt字符串的条目给找出来(只要Url中包含robots.txt的都给过滤掉)。
前瞻的语法是:
(?!匹配模式)我们先来实现第一个目标――匹配不以特定字符串开头的条目。
这里我们因为要排除一段连续的字符串,因此匹配模式非常简单,就是。实现如下:
用Expresso我们可以看到结果确实过滤掉8号的数据。
接下来,我们来实现第二个目标――排除包含特定字符串的条目。
按照我们上面写法,我照葫芦画瓢了一下:
^.*?(?!robots\.txt).*?$
这段正则用大白话描述就是:开头任意字符,然后后面不要跟着robots.txt连续字符串,然后再跟着任意个字符,字符串结尾。 运行测试,结果发现:
没有达到我们想要的效果。这是为什么呢?我们给上面的正则表达式加上两个捕获分组调试一下:
^(.*?)(?!robots\.txt)(.*?)$
测试结果:
我们看到,第一个分组啥都没有匹配到,而第二个分组却匹配了整个字符串。再回过头来好好分析一下刚才那个正则表达式。实际上,当正则引擎解析到A区域的时候,就已经开始执行B区域的前瞻工作。这个时候发现当A区域为Null的时候匹配成功――.*本来就允许匹配空字符,前瞻条件又满足,A区域后面紧跟着的是“2009”字符串,而并不是robots。因此整个匹配过程成功匹配到所有条目。
分析出原因之后我们对上述的正则进行修正,将.*?移入前瞻表达式,如下:
^(?!.*?robots).*$
php中用正则实现不包括某个字符串的实现方法
preg_match(&/^((?!abc).)*$/is&, $str);
完整代码示例
$str = &dfadfadf765577abc55fd&;
$pattern_url = &/^((?!abc).)*$/is&;
if (preg_match($pattern_url, $str))
echo &不含有abc!&;
echo &含有abc!&;
结果为:false,含有abc!
同时匹配,包含字符串 &abc&,而且不包含字符串 &xyz&的正则表达式:
preg_match(&/(abc)[^((?!xyz).)*$]/is&, $str);
该方法有效,本人使用方法如下:
(?:(?!&\/div&).|\n)*? //匹配不含&/div&的一个字符串
但最终使用中结果是发现,该方法效率极其低下,在处理非常短文字(要匹配该正则式的相同部分的有十几个字,或者最多几十个)时间可以考虑使用,但当用于大篇幅文章解析或多处需要改种匹配时间应不使用,考虑用其他方法替代(如:先解析出要匹配该段正则式的文字,然后验证其中是否存在某段文字),正则表达式对于匹配不含特定字符串的文字段时并不是非常有效的方法.
经常我们会遇到想找出不包含某个字符串的文本,程序员最容易想到的是在正则表达式里使用,^(hede)来过滤”hede”字串,但这种写法是错误的。我们可以这样写:[^hede],但这样的正则表达式完全是另外一个意思,它的意思是字符串里不能包含‘h',‘e',‘d'三个但字符。那什么样的正则表达式能过滤出不包含完整“hello”字串的信息呢? 事实上,说正则表达式里不支持逆向匹配并不是百分之百的正确。就
常见函数 strstr($str, “abc”);
正则匹配 preg_match(”/(abc)?/is”, $str);
但是要匹配一个字符串中,不包含某字符串,用正则就比较麻烦了
如果不用正则 !strstr($str, “abc”); 就可以解决问题了
但是用正则呢,就只有这样了,”/^((?!abc).)*$/is”
//----------------------------
使用Excel中的VBA测试如下(匹配式为:^((?!2950).)*$): Sub Regs() Dim RegEx As Object Set RegEx = CreateObject(&VBScript.regexp&) Dim s, mat s = && RegEx.Pattern = &^((?!2950).)*$&qu
本文实例讲述了php使用正则表达式进行字符串搜索的方法。分享给大家供大家参考。具体实现方法如下:
&?php $string_to_search = &jb51.net&; $regex = &/tor/&; $num_matches = preg_match($regex, $string_to_search); if ($num_matches
JavaScript中的正则表达式解析正则表达式(regular expression)对象包含一个正则表达式模式(pattern)。它具有用正则表达式模式去匹配或代替一个字符串(string)中特定字符(或字符集合)的属性(properties)和方法(methods)。要为一个单独的正则表达式添加属性,可以使用正则表达式构造函数(constructor function),无论何时被调用的预设
虽然代码不多,但简单明了
preg_match('/^(?!string)/', 'aa') === true
这个用来验证一个字符串是否是非'string'开头的, 在perl或支持perl的正则表达式的语言(如php)中,可以用前看声明来做到这一点,正则表达式是:
preg_match('/.*(?!\.txt)$/', 'aa')
var reg=/正则表达式/; boolean reg.test(要验证的字符串); js引擎会将/正则表达式/“”转换成一个RegExp对象,当字符串满足正则表达式的要求事,返回true。 我写的一个表达式验证示例:功能如下: 用户名,不能为空 密码6为数字 密码确认,两次输入密码必须相同 身份证号码必须是15位,或者是18位,最末尾也可以是X(该功能还没有写,有时间再补上)
正则表达式定义了一个字符串的规则。最简单的正则表达式不包含任何保留字。例如,正则表达式hello只和字符串“hello”匹配。 一般的正则表达式使用了某些特殊的结构,所以它能匹配更多的字符串。例如,正则表达式hello|word既能匹配字符串“hello”也能匹配字符串“word”。举一个更复杂一点的例子,正则表达式b[an]*s可以匹配字符串“bananas”、“baaa
实现的效果:在字符串中abcdefgname='test'sddfhskshjsfsjdfps中获取name的值test
实现的机制:通过replace的回调函数获取。
var str = &abcdefgname='test'sddfhskshjsfsjdfps&; var reg = /name='((\w|-|\s)+)/ str.
java正则表达式提供了比较丰富的类库,大大简化了这个过程。下面列出常用的基本语法: * + ? ^ $ [] () | / \ \d \D \w \W {} {n} {n,m}等, 要注意的是“|”或符号。它可以匹配单个字符和字符串。如:t[aeio]n只匹配tan,ten,tin,ton。但不匹配toon,因为在方括号内只能匹配单个字符,要匹配toon,使用t(a|e|i|o|oo)n就可以实
如果您想要去掉字符串开始和结束的空白可以使用PHP内部函数trim() 。但是, 我们经常想完全清除空白。需要把开始和结束的空白清除掉,将多个空白变为一个空白,使用一个规则来处理同样的类型的其它空白。
完成这些可以使用PHP的正则表达式来完成
下例可以去除额外Whitespace
&?php $str = & This line contains\tlib
在oracle中使用正则表达式截取字符串
--以下两条语句,将summary按-分解为两段字符串 regexp_substr(summary, '[^\-]+', 1, 1) as _work regexp_substr(summary, '[^\-]+', 1, 2) as _home --查询语句 select summary, regexp_substr(summary, '[^\-]+
正则表达式 获取两个指定字符之间字符串
本帖最后由 unloserv 于
15:19:24 编辑
&kkkkkaaaa f你n24j简介 kaaaakkkkkkkkkaaaa f我n24j简介 kaaaakkkk&
获得第一对f和k之间的字符串
&你n24j简介&
------解决方案--------------
已经是第二次遇到同样的问题了,要匹配的字符串里含有中文,例如“&你好&&Edward&”,我希望取出Edward的名字,所以正则表达式为“&[^&]*&&([^&]*)&”,匹配后只要取group(1)即可。在一台装有jdk1.4.2_06国际版的机器上,运行正常,但在装jdk1.4.2_01的机器上,则完全不能匹配。卸载原来的jdk,换
正则表达式可以: o测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证 o替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字 o根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字 正则表达式语法 一个正则表达式就是由普通字符(例如字符 a
///&summary& ///快速验证一个字符串是否符合指定的正则表达式。 ///&/summary& ///&paramname=&_express&&正则表达式的内容。&/param& ///&paramname=&_valu
我使用DW 这个所见所得的编辑器来写html时,喜欢写上注释,如&!-- header --& 等等的注释,在一次比较大的改动时,需要批量查找替换,为了批量操作,于是我写了一个正则表达式来进行处理。 查找:
(\r\n|\n|.)*?&\!-- header --&
效果如图:
还有一个常用的就是字符串之间的字符 如:查找&!-- he
函数功能:replace函数返回根据正则表达式进行文字替换后的字符串的复制。
函数格式:stringObj.replace(rgExp, replaceText)
参数:字符串stringObj,rgExp正则表达式,replaceText所替换的内容
本文涉及的内容包括字符串创建,正则表达式隐式创建对象,创建正则表达式,进行replace方法的使用匹配
示例代码:
[code] &lt
- (NSUInteger)analyseRX:(NSString *)string withPatternString:(NSString *)patternString {
// \\[[^\\]]+\\] 用以匹配字符串中所出现的 [*] 的个数 &
作为一个概念而言,正则表达式对于Python来说并不是独有的。但是,Python中的正则表达式在实际使用过程中还是有一些细小的差别。 本文是一系列关于Python正则表达式文章的其中一部分。在这个系列的第一篇文章中,我们将重点讨论如何使用Python中的正则表达式并突出Python中一些独有的特性。 我们将介绍Python中对字符串进行搜索和查找的一些方法。然后我们讲讨论如何使用分组来处理我们查找
感谢AKA及作者。
Perl 中的正则表达式正则表达式的三种形式
正则表达式中的常用模式
正则表达式的 8 大原则
  正则表达式是 Perl 语言的一大特色,也是 Perl 程序中的一点难点,不过如果大家能够很好的掌握他,就可以轻易地用正则表达式来完成字符串处理的任务,当然在 CGI 程序设计中就更能得心应手了。下面我们列出一
PHP和正则表达式 一个正则表达式是一个特定的格式化模式,可以用来找出一个字符串在另一个字符串中的使用情况。几个编程语言,包括VisualBasic,Perl,JavaScript和PHP都支持正则表达式,希望在这篇入门指导的结束,Mitchell(作者自己)可以让你在PHP程序中能应用一些基本的正则表达式。正则表达式是在各种各样的程序语言中突出的古怪特征中的一种,但是由于它们看起来是
正则表达式可以: o测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证 o替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字 o根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字 正则表达式语法 一个正则表达式就是由普通字符(例如字符 a
正则表达式概述
正则表达式在程序设计语言中存在着广泛的应用,特别是用来处理字符串。如匹配字符串、查找字符串、替换字符串等。可以说,正则表达式是一段文本或一个公式,它是用来描述用某种模式去匹配一类字符串的公式,并且该公式具有一定的模式。 本小节将介绍正则表达式的基本概念、第一个正则表达式,以及测试正则表达式的工具Code Architects Regex Tester。
什么是正则表达式
js中的正则表达式比起C#中的正则表达式要弱很多,但基本够用了1定义正则表达式2关于验证的三个这则表达式方法3正则表达式式的转义字符1定义正则表达式在js中定义正则表达式很简单,有两种方式,一种是通过构造函数,一种是通过//,也就是两个斜杠。例如
var re =new RegExp(&\\?(\\w{1,}=\\w{1,}&am
如果你不熟悉这个术语,那么“正则表达式”(Regular Expression)就是一个字符构成的串,它定义了一个用来搜索匹配字符串的模式。
正则表达式30分钟入门教程
常用正则表达式
许多语言,包括Perl、PHP、Python、JavaScript和JScript,都支持用正则表达式处理文本,一些文本编辑器用正则表达式实现高级“搜索-替换”功能。那么Java又怎样呢?本文写作
JavaScript 表单验证正则表达式大全 利用正则表达式判断是否是0-9的阿拉伯数字
function regIsDigit(fData) { var reg = new RegExp(&^[0-9]$&); return (reg.test(fData)); }
利用这则表达式获取字符串的长度
function regDat
所谓的正则表达式,就是用一类元字符(不表示本身意义,而表示统配或其他意义),组 合其他字符所编数出来的,能够匹配符合条件的字符。 正则表达式有基本正则表达式和扩展正则表达式两大类, 下面给大家介绍一下基本正则表达式和扩展正则表达式的一些常用的字符, 基本正则表达式:
正则表达式语法 一个正则表达式就是由普通字符(例如字符a到z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
这里有一些可能会遇到的正则表达式示例:
JScriptVBScript匹配 /^\[\t]
功能:使用正则表达式模式对字符串执行查找,并将包含查找的结果作为数组返回
函数格式:stringObj.match(rgExp) stringObj为字符串必选 rgExp为正则表达式必选项
返回值:如果能匹配则返回结果数组,如果不能匹配返回null
&html& &script language=&javascript& type
一.linux文本查找命令 在说linux正规表达式之前,还介绍下linux中查找文本文件常用的三个命令: 1.grep : 最早的文本匹配程序,使用POSIX定义的基本正则表达式(BRE)来匹配文本。 2.egrep : 扩展式grep,其使用扩展式正规表达式(ERE)来匹配文本。 3.fgrep : 快速grep,这个版本匹配固定字符串而非正则表达式。并且是唯一可以并行匹配多个字符串的版本。
正则表达式:语法:/expression/,斜杠表示起始位置创建方式:
1、var regObj = new RegExp(&pattern&,[,&flags&]); pattern:必选项,正则表达式的字符串;
正则表达式就是处理字符串的方法,它以行为单位来进行字符串的处理行为,正则表达式通过一些特殊符号的辅助,可以让用户轻易达到查找、删除、替换某特定字符串的处理程序。 正则表达式基本上就是一种“表示法”,只要工具程序支持这种表示法,那么该工具程序就可以利用正则表达式处理字符串。例如vi,grep,awk,sed等。 正则表达式和之前的bash通配符是两个完全不同的东西,两者毫无关系,这个要注意下。 #
在计算机科学中,正则表达式用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在WEB开发中,正则表达式通常用来检测、查找替换某些符合规则的字符串,如检测用户输入E-mai格式是否正确,采集符合规则的页面内容等等。
今天我将分别用PHP和Javascript向大家介绍WEB开发中最常用最实用的正则表达式及其用法,正则表达式是一门学科,不可能使用一篇文章来讲解完,理论的东西网上很多,有兴趣
正则表达式语法 一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 这里有一些可能会遇到的正则表达式示例:
Visual Basic Scripting Edition VBScript 匹配
/^\[ \t]*$/ &quot
正则表达式的功能实在太强大了~以下为找到的一个关于正则表达式基本语法的介绍:
首先让我们看两个特殊的符号'^'和'$'。他们的作用是分别指出一个字符串的开始和结束。例子如下:
&^The&:表示所有以&The&开始的字符串(&There&,&Thecat&等); &ofdespai
由于我对正则不是很清楚,我想求取把字符串“str,DGK,rDJK,DJKl,DGK,end”替换为“str,MSN,rDJK,DJKl,MSN,end” 求匹配式的写法。
&SCRIPT LANG
下面通过一些例子来说明使用正则表达式来处理一些工作中常见的问题。 1. REGEXP_SUBSTR REGEXP_SUBSTR 函数使用正则表达式来指定返回串的起点和终点,返回与source_string 字符集中的VARCHAR2 或CLOB 数据相同的字符串。 语法: --1.REGEXP_SUBSTR与SUBSTR函数相同,返回截取的子字符串 REGEXP_SUBSTR(srcstr, pa
我们要解析一个HTML文档时可利用正则表达式取得标签内容 例子: 以从字符串中取出所有A标签的id号和内容为例: &aid=&1&target=&_blank&&aaaaaaaaaa&/a& 正则表达式: &a[^&]*id[^&]*=[^&]*&(?&ID&
JavaScript的RegExp对象和String对象定义了使用正则表达式来执行强大的模式匹配和文本检索与替换函数的方法.   在JavaScript中,正则表达式是由一个RegExp对象表示的.当然,可以使用一个RegExp()构造函数来创建RegExp对象,也可以用 JavaScript 1.2中的新添加的一个特殊语法来创建RegExp对象.就像字符串直接量被定义为包含在引号内的字符一样,正38007人阅读
Linux(25)
之前一篇博文讲了下正则表达式的一些基本使用,这次讲一下高级的。还是那句话,要多用,才能够记住并留在你的大脑皮层。
1. 匹配一个或多个连续字符
用+符号, a+,意思是匹配1个或多个字符a;[0-9]+,意思是匹配一个或多个数字
在vim中 + 语法有点不同,要用 '\+',如左示例。
note:[\w.] == [\w\.],像. &+ 这样的元字符,在字符集中可以不转义,但是转义一下也没问题。
* 用法跟+相同,但是匹配0个或多个连续字符
& 匹配0或多个数字,然后跟着abc三个字母
? 匹配0个或1个字符(或字符集合)
&?在vim中的语法也有点不同,要写成 '\?',如左示例
另外,可以用{}来设置重复次数,例如
a{9} & & 匹配连续9个a
[0-9]{9} 匹配连续9个数字字符
{2} & & &重复2次
{2,4} & &重复2-4次
{2,} & & 重复至少2次,无上限
注意{}的用法在vim中也有点不同,左{前要加一个‘\’.
元字符的贪婪型和懒惰型版本
* & & & & & *?
+ & & & & & +?
{n,} & & & &{n,}?
& & & &&& & & &&
上面是一个例子,左边是贪婪模式,右边本来的正则应该是&[Bb]&.*?&\/[Bb]&,但是好像vim不支持,就找了上面途中所示的方法,效果是一样的,{-}的意思是最短匹配,注意{}在vim中的用法,要加一个\,再看下第3个例子,帮助理解。
2. 位置匹配
\b & 匹配一个单词的开头或末尾
\B & 不匹配一个单词边界 & (这个vim也不支持,不演示了,不过notepad++支持,我试过)
\& & 匹配一个单词的开头 & 不是所有的编辑器都支持
\& & 匹配一个单词的结束
要注意下3个匹配结果的不同,另外,\b不被vim支持,所以只能用后面两种形式。
字母数字下划线是作为单词边界的字符,因此那个+符号,其实跟空格没啥区别。
^ & &匹配一个字符串的开头
$ & &匹配一个字符串的结束
很多正则表达式的实现都支持使用一些特殊的元字符去改变另外一些元字符的行为,用来启动分行匹配模式的(?m)记号就是其中一个例子。分行匹配模式使得正则表达式引擎把行分隔符当作一个字符串分隔符来对待。
在分行匹配模式下,^ 不仅匹配正常的字符串开头,还将匹配行分隔符(换行符)后的开始位置(这个位置不可见);类似地,$ 不仅匹配正常的字符串结尾,还将匹配行分隔符(换行符)后面的结束位置。
在使用时,(?m)必须出现在整个模式的最前面,例如下面的例子:
在匹配模式前面加上(?m)后,vim又不支持了,我用notepad++重新尝试了一下,(?m)加与不加效果好像没啥区别,都能够把3行注释找出来。
3. 使用子表达式
attention:
把必须匹配的情况考虑周全并写出一个匹配结果符合预期的正则表达式很容易,但把不需要匹配的情况也考虑周全并确保它们都将被排除在匹配结果之外往往要困难得多
子表达式,用()来定义,在vim中要用\(\)
常见用途: 对重复次数元字符的作用对象做出精确的设定和控制; 对|操作符的OR条件做出准确的定义; 如有必要,子表达式还允许嵌套使用。
上面的两条正则的匹配结果是一样的,但是右边的实例使用了子表达式。
'|'是正则里的'或'运算符
上面两个例子,右边的将19|20作为一个子表达式,左边的正则'|'将其两边的部分作为整体来看待,看成了19和20\d{2},因此左图中之匹配到了19而不是完整的1988.
精确匹配ip,只有0-255才可以的,有下面几种情况:
1)任何一个1位或2位数字
2)任何一个以1开头的3位数字
3)任何一个以2开头,第2位数字在0-4之间的3位数字
4)任何一个以25开头,第3位数字在0-5之间的3位数字
我擦,构造了一个有点长的正则表达式,给哥们来了个下面这个提示。
那条正则:\(\(\(\d\{1,2}\)\|\(1\d\{2}\)\|\(2[0-4]\d\)\|\(25[0-5]\)\)\.\)\{3}\(\(\d\{1,2}\)\|\(1\d\{2}\)\|\(2[0-4]\d\)\|\(25[0-5]\)\)
换用notepad++,如下匹配,只有1个合法ip
正则:\b(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\b
终于将所有不合法的ip排除在外了。
好吧,这篇暂时写到这里了,还有点东西,再写一篇吧。
水平有限,如果有朋友发现错误,欢迎留言交流
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:394389次
积分:3905
积分:3905
排名:第5705名
原创:64篇
评论:69条
文章:14篇
阅读:57642
阅读:5566
文章:14篇
阅读:155303966,690 八月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
正则表达式(五):浅谈两种匹配操作
正则表达式(五):浅谈两种匹配操作
被首富的“一个亿”刷屏?不如定个小目标,先把握住的优惠吧!
相关厂商内容
相关赞助商
QCon全球软件开发大会上海站,日-22日,上海宝华万豪酒店,!
为保证完整,我们需要考虑足够多的变体,覆盖所有情况。一般来说,要提取的数据都只有概念的描述(比如,提取一个电子邮件地址,提取一个身份证号),如果没有拿到完整规范的特征描述,可能只能凭经验总结出几条特征,然后逐步完善,也就是不断考虑新的情况,照顾到各种情况。
拿&提取文本中的浮点数字符串&为例。最容易想到的情况,就是3.14、.36之类,也就是&数字字符串 + 小数点 + 数字字符串&,所以用表达式『\d+\.\d+』,按照我们上一篇文章说过的&与或非&,三个部分都是必须出现的,所以这个表达式似乎是没问题了。
但是有些时候,0.7是写作.7的,上面的表达式无法照顾这种情况,所以必须修改表达式:整数部分是可能出现也可能不出现的,所以小数点之前的\d+应该改为\d*,就成了『\d*\.\d+』。
但是且慢,浮点数还包括负数,比如-0.7,但现在这个表达式无法匹配最开始的符号,所以还应该改成『-?\d*\.\d+』。
-?\d*\.\d+
但仅仅保证完整性还不够,提取的另一方面是精确,就是排除掉那些&能够由正则表达式匹配,但其实并非期望&的字符串,所以我们还需要仔细观察目前的正则表达式,适当添加限制条件。
仍然用上面的正则表达式作例子,『-?\d*\.\d+』中,『-?』和『\d*』都是可能出现的元素,所以它们可能都不出现,这时候表达式能匹配.7之类,没有错;如果只出现了『\d*』能匹配的文本,可以匹配3.14之类,也没有错;但是,如果只出现『-?』呢?-.7,通常来说,负的浮点数是应该写作-0.7的,而-.7显然是不合法的。所以,这个表达式应该修改为『(-?\d+|\d*)\.\d+』。
(-?\d+|\d*)\.\d+
事情到这里就完整了吗?似乎还不是。我们知道有些地方,日期字符串是&&的形式,如果你要处理的文本中不包含这种日期字符串还好,否则,上面的表达式会错误匹配2010.12.22或者2010.12.22。为了避免这种情况,我们需要给表达式加上更多的限制。最直接想法就是,限定表达式两端不能出现点号.,变成『(?!&.)(-?\d+|\d*)\.\d+(?!.)』。
(?!&.)(-?\d+|\d*)\.\d+(?!.)
这样确实避免了的错误匹配,但它也造成了新的问题,比如&&the value of & is 3.14. Therefore&&,3.14本来是我们需要提取的浮点数,但加上这个限制之后,因为3.14之后的有一个作为英文句号使用的点号,所以3.14无法匹配。仔细观察我们要排除的这类字符串,我们发现点号.的另一端仍然是数字,而用作句号的点号,另一端必定不是数字(一般是空白字符,或者就是字符串的开头/末尾),所以应当把限制条件表达的更精确些,变为『(?!&\d.)(-?\d+|\d*)\.\d+(?!.\d)』。
(?!&\d.)(-?\d+|\d*)\.\d+(?!.\d)
好了,关于浮点数的匹配就讲到这里。回过头想想得到最后的这个表达式,我们发现,如果要用正则表达式匹配,必须兼顾完整和精确,通常的做法就像这个例子中的一样:先逐步放宽限制,保证完整;再添加若干限制,保证精确。
提取数据时还有一点需要注意,就是效率。有时要处理的文本非常长,即便进行简单的字符串查找都很费力,更不用说可能出现各种变体的正则表达式了。这时候就应当尽量减少&变化&的范围。比如知道文本中只包含一个双引号字符串,希望将它提取出来,正则表达式写成了『&.*&』。在文本不长时这样还可以接受,如果文本很长,『.*』这类子表达式就会导致大量的回溯,因为『.*』的匹配过程是这样的:
观察匹配过程就会发现,如果字符串很长,而引号字符串又出现在比较靠前的位置,比如&quoted string& and long long long text&,匹配时就需要进行大量的回溯操作,严重影响效率。如果这种问题并不是任何情况下都可能发生,但效率确实非常重要的,如果正则表达式编写不当,可以产生极为严重的影响,比如ReDos(正则表达式拒绝服务),具体情况可以参考。
另一方面,正则表达式提取的效率,不仅与正则表达式本身有关,也与调用的API有关。如果文本很大,要提取出的结果很多,集中到一次操作进行,就可能影响性能,所以条件容许(比如只需要逐步提取出来,依次处理),就可以&逐步进行&,下面的表格列出了常用语言中的提取操作。
Matcher.find()
只能逐步进行
preg_match(regex, string, result)
preg_match_all(regex, string, result)
一次性进行
Regex.match(string)
Regex.matches(string, regex)
一次性进行
re.find(regex, string)
re.finditer(regex, string)
re.findall(regex, string)
一次性进行
Regexp.match(text)
只能找到第一次匹配
string.index(Regexp, int)
string.scan(Regexp)
一次性进行
JavaScript
RegExp.exec(string)
一次性进行
string.match(RegExp)
一次性进行
一次性提取所有匹配结果的操作这里不多说,我们要补充讲解的是,在&逐步进行&时,如何真正保证&逐步&?或者说,在第二次调用匹配时,如何保证是&承接&第一次调用,找到下一个匹配结果。通常的做法有几种,以下分别介绍。例子统一使用字符串为&123 45 6&,查找其中的数字字符串,依次输出123、45、6。
如果采用的是面向对象式处理,表示匹配结果的对象,可能可以&记住&匹配的位置,下次调用时自动&继续&,Java就是这样,循环调用Matcher.find()方法,就可以逐个获得所有匹配,在.NET中,是循环调用Match.NextMatch()。
代码(以Java为例)
String str = &123 45 6&;
Pattern p = pile(&\\d+&);
Matcher m = p.matcher(str);
while (m.find()) {
System.out.println(m.group());
如果不是面向对象式处理,无法记录匹配的状态信息,则可以手动指定偏移值。多数语言都有办法在匹配时指定偏移值,也就是&从字符串的offset位置开始尝试匹配&。如果要逐一获得所有匹配,每次将偏移值指定为上一次匹配的结束位置即可。注意,字符串处理时可能有人习惯将偏移值指定为&上一次匹配的起始位置+1&,但正则表达式处理时这样是不对的,比如正则表达式是『\d+』,而字符串是&123 45 6&,第一次匹配的结果是123,如果把偏移值设定为&上一次匹配的起始位置+1&,之后的匹配结果就是23,3&&。在PHP、JavaScript、Ruby中,通常采用这种办法。
代码(以PHP为例)
$string=&123 45 6&;
$regex=&/\\d+/&;
$matched = 1;
$oneMatch=array();
$lastOffset = 0;
$matched = preg_match($regex, $string, $oneMatch, PREG_OFFSET_CAPTURE, $lastOffset);
while ($matched == 1) {
$lastOffset = $oneMatch[0][1] + strlen($oneMatch[0][0]);
echo $oneMatch[0][0].&&br /&&;
$matched = preg_match($regex, $string, $oneMatch, PREG_OFFSET_CAPTURE, $lastOffset);
第3种办法是使用迭代器,Python的re.finditer()会得到一个迭代器,每次调用next(),就会获得下一次匹配的结果。这种办法目前只有Python提供,其它语言尚不具备。
代码(以Python为例)
for match in re.finditer(&\\d+&, &123 45 6&)
print match.group(0)
另一类&匹配&是数据验证,也就是&检查字符串能否完全由正则表达式匹配&,它主要用来测试和保证数据的合法性。比如有些网站要求你设定密码,密码只能由数字或小写字母构成,长度在6到12个字符之间,如果输入的密码不符合条件,则会提示你修改,这个任务,一般使用JavaScript的正则表达式来完成。
初看起来,这也是用正则表达式在字符串中查找匹配文本。但仔细想想,两者又不一样:一般来说,提取时正则表达式匹配的开始/结束位置都是不确定的,需要逐次试错,才能决定;验证时,同样需要考虑准确性,但效率并不是重点考虑的因素(一把验证的文本是用户名、手机号、密码之类,不会太长),虽然也要求准确性,但匹配的开始/结束位置都是确定的,只要从文本的开头验证即可,不用反复推进-尝试;而且只要发现任何一个&硬性&条件无法满足(比如长度、锚点),即可失败退出。
正因为验证操作有这些特点,有些语言中提供了专门的方法进行正则表达式验证。如果没有,我们也可以使用简单的查找功能,只是在正则表达式的首尾加上匹配字符串起始/结束位置的锚点来定位,这样既保证表达式匹配的是整个字符串,也可以在无法匹配时尽早判断失败退出。
常见语言中的验证方法
String.matches(regex)
专用于验证,返回boolean值,不需要『^』和『$』
preg_match(regex, string) != 0
preg_match返回匹配成功的次数,需要『^』和『$』
Regex.IsMatch(string, regex)
专用于验证,返回boolean值,不需要『^』和『$』
re.search(regex, string) != None
成功则返回True,否则返回False,需要『^』和『$』
re.match(regex, string) != None
成功则返回True,否则返回False,需要『$』
Regexp.match(text) != nil
Regexp.match(text)返回匹配成功的起始位置,若无法匹配则返回nil,需要『^』和『$』
JavaScript
Regexp.test(string)
专用于验证,返回boolean值,需要『^』和『$』
前面说过,在验证时,文本的开始/结束位置是预先知道的,所以验证的表达式编写起来更加简单。比如之前匹配浮点数的表达式,我们首先得到的是『(-?\d+|\d*)\.\d+』,在进行数据提取时,需要在两端加上环视,防止错误匹配其它字符;但是如果是验证浮点数,就不需要考虑两端的环视,应该/不应该出现什么字符,直接在首尾加上『^』和『$』即可,所以验证用的表达式是『^(-?\d+|\d*)\.\d+$』。
我们甚至可以简单将各个条件叠加起来,直接得到最后的表达式,比如下面这个例子:
需要验证密码字符串,前期的分析总结出5条明确的规则:
密码的长度在6-12个字符之间
只能由小写字母、阿拉伯数字、横线组成
开头和结尾不能是横线
不能全部是数字
不容许有连续(2个及以上)的横线
下面依次列出对应5条规则的表达式:
密码长度在6-12个字符之间:其形式类似『.{6, 12}』
只能由小写字母、阿拉伯数字、横线组成:所有的字符都只能由『[0-9A-Za-z-]』匹配
开头和结尾不能是横线:开头『^(?!-)』,结尾『(?&!-)$』
不能全部是数字,也就是说必须出现一个『[^0-9]』或者『\D』
不容许有连续(2个及以上)的横线,也就是说不能出现『--』
如果用来提取数据,就必须把这5条规则糅合到一起。前3条规则比较好办,可以合并为『^(?!-)[0-9A-Za-z-]{6,12}(?&!-)$』,但它与第4和第5个条件合并都不简单。
与第4条规则合并的难点在于,我们无法确定这个『[^0-9]』出现的位置,如果简单改为『^(?!-)[0-9A-Za-z-]{6,12}[^0-9][0-9A-Za-z-]{6,12}(?&!-)$』,看似正确,却无法保证整个字符串的长度在6-12之间&&目前这个表达式的长度在13(6+1+6)到25(12+1+12)之间。这显然有问题,但照这个方式也确实无法保证整个字符串的长度,因为我们无法跨越『[^0-9]』,为两端『[0-9A-Za-z-]』的量词建立关联,让它们的和为5-11之间。同样,与第5条规则的合并也存在这类问题,因为我们无法确认『--』的出现位置。
看起来,把这5条规则糅合成一个正则表达式,找到能够匹配的文本,真不是件容易的事情。不过,如果我们要做的只是验证,不妨换个思路:我们要匹配的并不是所有的文本,而是文本的开始位置,它后面的文本满足5个条件,而每个条件都可以不用实际匹配任何文本,而用环视来满足。
对应5条规则的环视表达式依次是:
密码长度在6-12个字符之间:『^(?=.{6, 12}$)』
只能由小写字母、阿拉伯数字、横线组成:『^(?=[0-9A-Za-z-]*$)』
开头和结尾不能是横线:『^(?!-).*(?&!-)$』
不能全部是数字:『^(?=.*[^0-9])』(这里不需要出现$,只要出现了非数字字符就可以)
不容许有连续(2个及以上)的横线:『^(?!.*--)』
下面就是寻找这样一个文本起始位置,它后面的文本同时满足这5个条件。实际上,因为锚点并不真正匹配文本,所以多个锚点可以重叠在一起,因此我们完全可以寻找5个锚点,把它们串联起来:
『(^(?=.{6, 12}$))(^(?=[0-9A-Za-z-]*$))(^((?!-).*(?&!-)$))(^(?=.*[^0-9])(^(?!.*--))』
意思就是:先寻找这样一个字符串起始位置,它之后的字符串满足条件1;然后寻找这样一个字符串其实位置,它之后的字符串满足条件2;&& 如果能找到5个这样的字符串起始位置(实际上,因为只有一个字符串起始位置,所以这5个位置是重叠的),就算验证成功。
其实我们也可以不用那么多的括号,只用一个『^』即可:
『^(?=.{6, 12}$)(?=[0-9A-Za-z-]*$)(?=(?!-).*(?&!-)$)(?=.*[^0-9])(?!.*--)』
虽然&匹配&是正则表达式的常见操作,但细分起来,&匹配&又可分为提取和验证两种操作。
提取时需要照顾准确性和效率,因为此时字符串的起始/结束位置是不确定的,应当添加适当的环视结构,避免匹配了不期望的数据。
验证时对效率的要求并不高,因为验证的字符串一般都很短,而且验证的起始/结束位置都是确定的,直接在字符串两端添加^和$即可。而且验证有时候要比提取简单得多,我们可以改换思路,改&查找文本&为&查找位置&,针对验证时容许/不容许出现的每一个条件,写出对应的环视功能,作为一个将它们并列在一起。
余晟,程序员,曾任抓虾网高级顾问,现就职于盛大创新院,感兴趣的方向包括搜索和分布式算法等。翻译爱好者,译有《精通正则表达式》(第三版)和《技术领导之路》,目前正在写作《正则表达式傻瓜书》(暂定名),希望为国内开发同行贡献一本实用的正则表达式教程。
感谢对本文的策划和审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家加入到中与我们的编辑和其他读者朋友交流。
Author Contacted
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
satsun Studsio
Re: satsun Studsio
我感觉java中要这样写上面那个浮点字符串
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
通过个性化定制的新闻邮件、RSS Feeds和InfoQ业界邮件通知,保持您对感兴趣的社区内容的时刻关注。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?}

我要回帖

更多关于 正则表达式匹配时间 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信