显然,你可以使用 |
(管道符号)来表示 OR
,但是否有一种方式来表示 AND
?
具体而言,我想匹配包含某些短语的所有文本段落,但顺序不限。
显然,你可以使用 |
(管道符号)来表示 OR
,但是否有一种方式来表示 AND
?
具体而言,我想匹配包含某些短语的所有文本段落,但顺序不限。
使用非消耗性正则表达式
典型的表示方法(如Perl / Java)是:
(?=
表达式)
这意味着“匹配expr ,但在那之后继续在原始匹配点进行匹配。”
您可以使用任意数量的这些表达式,这将是“and”的关系。例如:
(?=匹配此表达式)(?=也匹配这个)(?=还有这个)
如果需要保存其中某些数据,甚至可以在非消耗性表达式内部添加捕获组。
你需要像其他回答者所说的那样使用前瞻,但是前瞻必须考虑其目标词和当前匹配位置之间的其他字符。例如:
(?=.*word1)(?=.*word2)(?=.*word3)
第一个正向前瞻中的 .*
可以匹配在 "word1" 之前任意数量的字符。然后,匹配位置被重置,第二个正向前瞻查找 "word2"。再次重置后,最后一部分匹配 "word3";由于它是你要检查的最后一个单词,所以不需要在前瞻中匹配,但这也没有坏处。.*
来消耗剩余的字符。使用 Perl 风格的表示法,可以写成:/^(?=.*word1)(?=.*word2)(?=.*word3).*$/m
'm'修饰符用于多行模式,它允许^
和$
匹配段落边界(在正则表达式中称为"行边界")。 在这种情况下,关键是不要使用's'修饰符,因为它允许点元字符匹配换行符以及所有其他字符。
最后,您需要确保匹配整个单词而不仅仅是长单词的片段,因此您需要添加单词边界:
/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m
看这个例子:
我们有两个正则表达式 A 和 B,我们想要匹配它们两个,伪代码如下:
pattern = "/A AND B/"
以下是不使用 AND 运算符的写法:
pattern = "/NOT (NOT A OR NOT B)/"
在 PCRE 中:
"/(^(^A|^B))/"
regexp_match(pattern,data)
(?=expr)
不行。这似乎取决于实现。 - Melebius^
不是表示字符串的开头吗? - Lambda Fairy^
只在字符类的开头表示取反。除非 CMake 做了一些特别奇怪的事情(以至于称他们的模式匹配语言为 "正则表达式" 可能会被视为误导或不正确),否则我猜测它对你起作用只是偶然事件。 - tripleee/(^(^A|^B))/
PCRE 中,^
的意思是“行首”,而不是否定。也许可以通过负向先行断言((?!…)
, 如(?!(?!A)|(?!B))
)运气好一些,但肯定不能用 ^
。 - SashaRegExp语法中的AND运算符是隐含的。
OR运算符必须用管道符号指定。
下面是一个RegExp示例:
var re = /ab/;
意思是字母a
和字母b
。它也适用于组合:
var re = /(co)(de)/;
这意味着组co
和 组de
。将(隐含的)"AND"替换为"OR"需要以下行:
这表示组co
和 组de
。如果要用"OR"替换隐式的"AND",则需要以下几行:
var re = /a|b/;
var re = /(co)|(de)/;
a
紧接着b
。相比之下,|
在同一位置检查两个模式。类似的版本是使用前瞻来测试是否匹配了两个模式;但是那么就不清楚匹配应该包含什么了。 - Karl Knechtel(abc)|(bca)|(acb)|(bac)|(cab)|(cba)
但是,如果有多于几个术语,这将生成非常长且可能效率低下的正则表达式。
如果您使用某些扩展的正则表达式版本,例如Perl或Java,则它们有更好的方法来处理这种情况。其他回答建议使用正向预查运算符。
在你的情况下,无法对多个匹配结果执行AND操作吗?伪代码示例:
regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...
为什么不使用awk?
使用awk,正则表达式中的AND和OR非常简单明了
awk '/WORD1/ && /WORD2/ && /WORD3/' myfile
正则表达式的结构总是隐含了顺序。要完成您想要的,您需要针对不同的表达式多次匹配输入字符串。
使用单个正则表达式无法实现您想要的操作。
(?=[1-9][0-9]{2})[0-9]*[05]\b
将是大于100且可被5整除的数字。
除了被接受的答案
我将为您提供一些实际示例,以便更好地理解。例如,假设我们有以下三行文本:
[12/Oct/2015:00:37:29 +0200] // only this + will get selected
[12/Oct/2015:00:37:x9 +0200]
[12/Oct/2015:00:37:29 +020x]
点击此处查看演示 演示
我们想要做的是选择加号,但只有在它在两个数字后面有一个空格,并且在四个数字之前。这些是唯一的限制条件。我们将使用以下正则表达式来实现:
'~(?<=\d{2} )\+(?=\d{4})~g'
注意,如果你分开表达式,它将给出不同的结果。
或者,也许你想选择标签之间的一些文本……但不包括标签!那么你可以使用:
'~(?<=<p>).*?(?=<\/p>)~g'
对于以下文本:
<p>Hello !</p> <p>I wont select tags! Only text with in</p>
这里查看演示 演示
(?:(?:(?(1)(?!))\b(phrase1)\b.*?|(?(2)(?!))\b(phrase2)\b.*?)){2}
,方式2:(?=.*\bphrase1\b)(?=.*\bphrase2\b)
,在这种情况下,匹配段落的定义未确定。|
的作用不同,这使问题变得混乱。|
检查当前位置是否匹配两个模式中的任意一个。它不检查字符串的其余部分是否至少包含其中之一。"and" 对应物将检查当前位置是否同时匹配两个模式;但显然您想搜索字符串并检查所有模式是否在其中某处匹配。 - Karl Knechtel