在某些正则表达式引擎中,不支持[否定]零宽断言(前瞻/后顾)。这使得排除某些内容变得极其困难(或许是不可能的?)。例如,“每行都没有“foo”的行”,就像这样:
^((?!foo).)*$
没有使用回顾(忽略复杂性和性能问题)可以实现相同的结果吗?
^((?!foo).)*$
没有使用回顾(忽略复杂性和性能问题)可以实现相同的结果吗?
更新:正如@Ciantic在评论中指出的那样,它会失败“在oo之前有两个ff”。
^(f(o[^o]|[^o])|[^f])*$
注意:在客户端仅否定匹配比使用上述正则表达式要容易得多。
该正则表达式假设每行以换行符结尾,如果不是,则参见C++和grep的正则表达式。
Perl、Python、C++和grep
中的示例程序都提供相同的输出。
#!/usr/bin/perl -wn
print if /^(f(o[^o]|[^o])|[^f])*$/;
#!/usr/bin/env python
import fileinput, re, sys
from itertools import ifilter
re_not_foo = re.compile(r"^(f(o[^o]|[^o])|[^f])*$")
for line in ifilter(re_not_foo.match, fileinput.input()):
sys.stdout.write(line)
c++
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*$");
//NOTE: "|$"s are there due to `getline()` strips newline char
std::string line;
while (std::getline(std::cin, line))
if (boost::regex_match(line, re))
std::cout << line << std::endl;
}
$ grep "^\(f\(o\([^o]\|$\)\|\([^o]\|$\)\)\|[^f]\)*$" in.txt
示例文件:
foo
'foo'
abdfoode
abdfode
abdfde
abcde
f
fo
foo
fooo
ofooa
ofo
ofoo
输出:
abdfode
abdfde
abcde
f
fo
ofo
f
,fo
或 barf
。但是这个可以:^(f(o([^o]|$)|[^o]|$)|[^f])*$
。 - Gumbofoo
有两个相似的字符并不意味着这个问答就是通用的。如果使用abc
会更好。 - Jean-François Fabre\A(?:$|[^f]++|f++(?:[^o]|$)|(?:f++o)*+(?:[^o]|$))*\Z
解释:
\A #Start of string
(?: #Non-capturing group
$ #Consume end-of-line. We're not in foo-mode.
|[^f]++ #Consume every non-'f'. We're not in foo-mode.
|f++(?:[^o]|$) #Enter foo-mode with an 'f'. Consume all 'f's, but only exit foo-mode if 'o' is not the next character. Thus, 'f' is valid but 'fo' is invalid.
|(?:f++o)*+(?:[^o]|$) #Enter foo-mode with an 'f'. Consume all 'f's, followed by a single 'o'. Repeat, since '(f+o)*' by itself cannot contain 'foo'. Only exit foo-mode if 'o' is not the next character following (f+o). Thus, 'fo' is valid but 'foo' is invalid.
)* #Repeat the non-capturing group
\Z #End of string. Note that this regex only works in flavours that can match $\Z
如果由于某种原因,您无法使用占位符量词或回顾后发现,但可以使用原子分组,则可以使用:
\A(?:$|(?>[^f]+)|(?>f+)(?:[^o]|$)|(?>(?:(?>f+)o)*)(?:[^o]|$))*\Z
^(?!.*foo)
:D 在这种情况下的解决方案是:^([^f]|(f+o)*f+([^fo]|o([^fo]|$)|$))*$
。我们甚至可以相当优雅地将其扩展到任意子字符串 "foo"...... 我很快会发布有关此内容的详细说明! - jaytea\A(?:$|[^s]++|s++(?:[^n]|$)|(?:s++n)*+(?:[^a]|$))*\Z
- Sarovgrep -v foo
grep -v foo
搜索"foo"并否定结果,OP说他希望正则表达式本身完成工作。但是假设要求是“包含'foo'且*不包含'bar'”,并且你只能执行一次正则表达式匹配怎么办?简单地否定结果就行不通了。 - Alan Mooregrep foo <file> | grep -v bar
。我提出这个问题是因为我无法在Emacs中弄清楚上面的示例并使其工作,但我能够在命令行上做到这一点。 - Zach Younggrep -v
或相似命令是最好的选择了。但OP说的是一个假设情况,即你不能反转匹配项,也不能使用前瞻断言。幸运的是,在现实世界中,这样的情况极其罕见。;) - Alan Moore^[A-Za-z0-9.$-]*$
并接受true
结果为有效,或者像这样:
[^A-Za-z0-9.$-]
并接受false
作为有效结果。
当然,这并不总是一个选项:例如有时你必须将表达式放在配置文件中或将其传递给另一个程序。但值得记住。 例如你的具体问题,如果你可以使用否定,那么表达式会简单得多。