`

【转】正则表达式的先行断言(lookahead)和后行断言(lookbehind)

阅读更多
正则表达式的先行断言和后行断言一共有4种形式:
(?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion)
(?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)
(?<=pattern) 零宽正向后行断言(zero-width positive lookbehind assertion)
(?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)
这里面的pattern是一个正则表达式。

如同^代表开头,$代表结尾,\b代表单词边界一样,先行断言和后行断言也有类似的作用,它们只匹配某些位置,在匹配过程中,不占用字符,所以被称为“零宽”。所谓位置,是指字符串中(每行)第一个字符的左边、最后一个字符的右边以及相邻字符的中间(假设文字方向是头左尾右)。

下面分别举例来说明这4种断言的含义。

(?=pattern) 正向先行断言
代表字符串中的一个位置,紧接该位置之后的字符序列能够匹配pattern。
例如对”a regular expression”这个字符串,要想匹配regular中的re,但不能匹配expression中的re,可以用”re(?=gular)”,该表达式限定了re右边的位置,这个位置之后是gular,但并不消耗gular这些字符,将表达式改为”re(?=gular).”,将会匹配reg,元字符.匹配了g,括号这一砣匹配了e和g之间的位置。

(?!pattern) 负向先行断言
代表字符串中的一个位置,紧接该位置之后的字符序列不能匹配pattern。
例如对”regex represents regular expression”这个字符串,要想匹配除regex和regular之外的re,可以用”re(?!g)”,该表达式限定了re右边的位置,这个位置后面不是字符g。负向和正向的区别,就在于该位置之后的字符能否匹配括号中的表达式。

(?<=pattern) 正向后行断言
代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配pattern。
例如对”regex represents regular expression”这个字符串,有4个单词,要想匹配单词内部的re,但不匹配单词开头的re,可以用”(?<=\w)re”,单词内部的re,在re前面应该是一个单词字符。之所以叫后行断言,是因为正则表达式引擎在匹配字符串和表达式时,是从前向后逐个扫描字符串中的字符,并判断是否与表达式符合,当在表达式中遇到该断言时,正则表达式引擎需要往字符串前端检测已扫描过的字符,相对于扫描方向是向后的。

(?<!pattern) 负向后行断言
代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配pattern。
例如对”regex represents regular expression”这个字符串,要想匹配单词开头的re,可以用”(?<!\w)re”。单词开头的re,在本例中,也就是指不在单词内部的re,即re前面不是单词字符。当然也可以用”\bre”来匹配。

对于这4个断言的理解,可以从两个方面入手:

1.关于先行(lookahead)和后行(lookbehind):正则表达式引擎在执行字符串和表达式匹配时,会从头到尾(从前到后)连续扫描字符串中的字符,设想有一个扫描指针指向字符边界处并随匹配过程移动。先行断言,是当扫描指针位于某处时,引擎会尝试匹配指针还未扫过的字符,先于指针到达该字符,故称为先行。后行断言,引擎会尝试匹配指针已扫过的字符,后于指针到达该字符,故称为后行。

2.关于正向(positive)和负向(negative):正向就表示匹配括号中的表达式,负向表示不匹配。

对这4个断言形式的记忆:

1.先行和后行:后行断言(?<=pattern)、(?<!pattern)中,有个小于号,同时也是箭头,对于自左至右的文本方向,这个箭头是指向后的,这也比较符合我们的习惯。把小于号去掉,就是先行断言。

2.正向和负向:不等于(!=)、逻辑非(!)都是用!号来表示,所以有!号的形式表示不匹配、负向;将!号换成=号,就表示匹配、正向。
我们经常用正则表达式来检测一个字符串中包含某个子串,要表示一个字符串中不包含某个字符或某些字符也很容易,用[^...]形式就可以了。要表示一个字符串中不包含某个子串(由字符序列构成)呢?
用[^...]这种形式就不行了,这时就要用到(负向)先行断言或后行断言、或同时使用。
例如判断一句话中包含this,但不包含that。
包含this比较好办,一句话中不包含that,可以认为这句话中每个字符的前面都不是that或每个字符的后面都不是that。正则表达式如下:
^((?<!that).)*this((?<!that).)*$ 或 ^(.(?!that))*this(.(?!that))*$
对于”this is the case”这句话,两个表达式都能够匹配成功,而”note that this is the case”都匹配失败。
在一般情况下,这两个表达式基本上都能够满足要求了。考虑极端情况,如一句话以that开头、以that结尾、that和this连在一起时,上述表达式就可能不胜任了。
如”note thatthis is the case”或者”this is the case, not that”等。
只要灵活运用这几个断言,就很容易解决:
^(.(?<!that))*this(.(?<!that))*$
^(.(?<!that))*this((?!that).)*$
^((?!that).)*this(.(?<!that))*$
^((?!that).)*this((?!that).)*$

这4个正则表达式测试上述的几句话,结果都能够满足要求。
上述4种断言,括号里的pattern本身是一个正则表达式。但对2种后行断言有所限制,在Perl和Python中,这个表达式必须是定长(fixed length)的,即不能使用*、+、?等元字符,如(?<=abc)没有问题,但(?<=a*bc)是不被支持的,特别是当表达式中含有|连接的分支时,各个分支的长度必须相同。之所以不支持变长表达式,是因为当引擎检查后行断言时,无法确定要回溯多少步。Java支持?、{m}、{n,m}等符号,但同样不支持*、+字符。Javascript干脆不支持后行断言,不过一般来说,这不是太大的问题。参见这里。

试验例子
sole sorry chilly high tight laughter
匹配h


匹配后面是t的h


匹配后面不是t的h



匹配前面是g的h


匹配前面不是g的h



先行断言和后行断言某种程度上就好比使用if语句对匹配的字符前后做判断验证。

转载地址:http://cnn237111.blog.51cto.com/2359144/749047


  • 大小: 14.9 KB
  • 大小: 14.4 KB
  • 大小: 15.3 KB
  • 大小: 15.3 KB
  • 大小: 15.4 KB
分享到:
评论

相关推荐

    正则表达式之——先行断言(lookahead)和后行断言(lookbehind).rar

    总结来说,先行断言和后行断言是正则表达式中的高级特性,它们提供了一种方式来控制匹配的位置,而不仅仅是简单的字符序列。通过熟练掌握这两种断言,我们可以在正则表达式中实现更复杂的逻辑,提高文本处理的精确度...

    微软的正则表达式教程

    此外,还要掌握预查(lookahead)和后顾(lookbehind)断言,这些可以实现更复杂的匹配逻辑。 微软的教程不仅会涵盖这些基础,还会深入到正则表达式的高级特性,如递归正则表达式、回溯控制和非贪婪匹配等。通过...

    正则表达式(有详细的解释和案例)

    正则表达式,简称为正则或regex,是一种强大的文本处理工具,用于匹配、查找、替换和提取字符串模式。在编程和数据处理中,正则表达式扮演着至关重要的角色,尤其是在文本分析、数据清洗、验证输入等方面。下面将...

    正则表达式的匹配规则

    本文将深入探讨正则表达式的匹配规则,帮助你理解和掌握这个强大的工具。 一、基础字符匹配 1. 字符匹配:正则表达式可以直接匹配单个字符,例如"a"匹配字母'a'。 2. 位置匹配:"^"表示行首,"$"表示行尾。"\b"匹配...

    正则表达式.7z

    正则表达式是一种强大的文本处理工具,用于匹配、查找、替换和分析字符串。在编程语言中,它被广泛应用于数据验证、数据提取、文本搜索和替换等场景。本压缩包"正则表达式.7z"包含了一份"笔记.txt",这份笔记详细...

    正则表达式宝典,强力推荐

    6. **零宽断言**:介绍如"lookahead"(前瞻断言)和"lookbehind"(后顾断言)这样的高级特性,它们允许在不消耗字符的情况下进行条件匹配。 7. **正则表达式引擎**:简述不同编程语言中正则表达式的实现差异,例如...

    余晟_实战正则表达式

    实战正则表达式第2讲可能涵盖了更复杂的正则表达式构造,如环视(lookaround)——前瞻断言(lookahead)和后顾断言(lookbehind),以及更高级的用法,如使用条件语句和非捕获组等。这些高级特性能够使正则表达式...

    C#正则表达式编程 清华红皮书系列

    正则表达式还支持高级特性,如前瞻断言(lookahead)、后瞻断言(lookbehind)、非捕获组((?:...))以及条件表达式等。这些特性使得正则表达式能够处理更复杂的匹配规则,例如匹配不包含特定子串的模式,或者根据...

    js正则表达式资料

    14. **高级用法**:如使用`lookahead`和`lookbehind`断言进行更复杂的模式匹配,以及使用`\p{Unicode}`和`\P{Unicode}`进行Unicode字符类匹配。 15. **学习资源**:从提供的文件列表来看,有《精通正则表达式》第三...

    javascript和正则表达式精典

    JavaScript 和正则表达式是Web开发中的两个重要概念,它们在构建交互式和动态网页时起着关键作用。正则表达式(Regular Expression)是一种强大的文本处理工具,用于模式匹配和字符串操作,而JavaScript作为浏览器...

    经典正则表达式完美教程

    正则表达式还支持多种扩展功能,如正向前瞻断言(positive lookahead)和正向后瞻断言(positive lookbehind),它们在匹配时不会消耗字符,仅用于判断特定模式是否出现在当前位置之前或之后。此外,条件表达式允许我们...

    最新的javascript正则表达式详解

    JavaScript中的正则表达式是进行文本处理和数据验证的强大工具,它允许我们通过模式匹配来查找、替换或分割字符串。本文将深入探讨JavaScript正则表达式的最新特性、语法以及常见用法。 一、正则表达式基础 1.1 ...

    javascript正则表达式全攻略

    1. 使用 `lookahead` 和 `lookbehind` 进行条件匹配,但JavaScript不完全支持零宽断言。 2. 使用 `flags` 属性获取或设置正则表达式的标志。 3. `RegExp.prototype.source` 获取正则表达式的源字符串。 通过以上...

    正则表达式断言、巡视(Assertions)、正向断言、反向断言介绍

    正则表达式的断言分为两大类:先行断言(Lookahead assertions)和后行断言(Lookbehind assertions)。先行断言又称正向断言,它有两种形式,分别是(?=pattern)和(?!pattern),其中(?=pattern)表示接下来的字符必须...

    正则表达式

    学习正则表达式时,通常会从基础语法开始,逐步接触更高级的概念,如前瞻断言(lookahead)和后瞻断言(lookbehind),它们允许我们在匹配某个模式的同时检查其前后是否有特定的模式。还有预定义字符类,如`\b`用于...

    delphi-RegTool.rar_delphi_delphi txt_delphi正则_正则表达式

    5. **高级特性**:如零宽断言(lookahead, lookbehind)、非捕获组、重复匹配等,都可以通过TRegEx类提供的方法实现。 导出功能的实现可能涉及到读取匹配结果并写入TXT文件的操作,这通常通过`TStringList`或`...

    正则表达式:运算符优先级介绍

    非零宽断言分为先行断言(lookahead)和后发断言(lookbehind)。例如,`(?)`表示后发断言,它会匹配紧跟在“abc”之后的任意位置。 六、连接 连接指的是没有分隔符时,字符之间的简单顺序排列。它表示的是字符或子...

    正则表达式学习与进步

    正则表达式(Regular Expression,简称regex)是用于匹配字符串的一种模式,广泛应用于文本处理、数据验证、搜索和替换等场景。它通过一种简洁而强大的语法来定义一系列字符或字符序列,可以用来检测一个字符串是否...

    Java正则表达式详解

    Java正则表达式是Java编程语言中用于处理字符串的强大工具,它基于Perl风格的正则表达式,允许开发者通过简洁的语法进行复杂的文本匹配、查找、替换和分割操作。在Java中,正则表达式主要通过`java.util.regex`包中...

    深入浅出正则表达式

    【深入浅出正则表达式】是一篇关于正则表达式的教程,主要涵盖了正则表达式中的关键概念和用法。以下是对这些知识点的详细解释: 1. **组与向后引用**: - **组**(Grouping)允许我们将一系列字符视为一个单元,...

Global site tag (gtag.js) - Google Analytics