我最近遇到了一个难题,以找到匹配的正则表达式:
5 个字符长的字符串,由小写英文字母组成,按 ASCII 升序排列
有效示例包括:
aaaaa
abcde
xxyyz
ghost
chips
demos
无效示例包括:
abCde
xxyyzz
hgost
chps
我目前的解决方案很笨拙。我使用正则表达式:
(?=^[a-z]{5}$)^(a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*)$
它使用非消耗性捕获组断言字符串长度为 5,然后验证字符串是否按顺序由小写英文字母组成(请参阅 Rubular(。
相反,我想在字符类中使用反向引用。像这样:
^([a-z])([1-z])([2-z])([3-z])([4-z])$
我脑海中解决方案(参见 Rubular(的逻辑是捕获第一个字符 [a-z],将其用作第二个字符类中的反向引用,依此类推。但是,1
,2
...在字符类中似乎是指 ASCII 值 1、2...有效匹配任何四或五个字符的字符串。
我有两个问题:
- 是否可以在字符类中使用反向引用来检查升序字符串?
- 这个难题有没有不那么黑客的解决方案?
我发布这个答案更多的是作为评论而不是答案,因为它的格式比评论更好。
与您的问题相关:
- 是否可以在字符类中使用反向引用来检查升序字符串?
不,你不能。如果您查看 backref 正则表达式部分,您将找到以下文档:
括号和反向引用不能在字符类中使用
括号不能在字符类中使用,至少不能用作元字符。在字符类中放置括号时,将其视为文本字符。因此,正则表达式 [(a(b] 匹配 a、b、( 和 (。
反向引用也不能在字符类中使用。正则表达式中的 \1 如 (a([\1b] 要么是错误,要么是不必要的转义文字 1。在 JavaScript 中,这是一个八进制转义。
关于你的第二个问题:
- 这个难题有什么不那么麻烦的解决方案吗?
恕我直言,您的正则表达式非常好,您可以在开始时将其缩短为:
(?=^.{5}$)^a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*$
^--- Here
正则表达式演示
如果你愿意使用 Perl (!(,这将起作用:
/^([a-z])((??{"[$1-z]"}))((??{"[$2-z]"}))((??{"[$3-z]"}))(??{"[$4-z]"})$/
由于有人通过使用Perl打破了僵局,我想这是一个
Perl解决方案。
请注意,这是一个基本的非正则表达式解决方案,恰好被
填充到 Perl 正则表达式中的代码结构中。
有趣的是,如果有一天你需要
正则表达式/代码的协同作用,这是一个不错的选择。
那么有可能,你可以使用一个非常复杂的模式,而不是一个简单的[a-z]
字符,并使用
检查与最后。
这就是力量!!
正则表达式^(?:([a-z])(?(?{ $last gt $1 })(?!)|(?{ $last = $1 }))){5}$
Perl 代码
use strict;
use warnings;
$/ = "";
my @DAry = split /s+/, <DATA>;
my $last;
for (@DAry)
{
$last = '';
if (
/
^ # BOS
(?: # Cluster begin
( [a-z] ) # (1), Single a-z letter
# Code conditional
(?(?{
$last gt $1 # last > current ?
})
(?!) # Fail
| # else,
(?{ $last = $1 }) # Assign last = current
)
){5} # Cluster end, do 5 times
$ # EOS
/x )
{
print "good $_n";
}
else {
print "bad $_n";
}
}
__DATA__
aaaaa
abcde
xxyyz
ghost
chips
demos
abCde
xxyyzz
hgost
chps
输出
good aaaaa
good abcde
good xxyyz
good ghost
good chips
good demos
bad abCde
bad xxyyzz
bad hgost
bad chps
啊,好吧,这是一个有限集合,所以你总是可以通过交替枚举它!这会在一个小的perl REPL中发出一种"蛮力"类型的正则表达式:
#include <stdio.h>
int main(void) {
printf("while (<>) { if (/^(?:");
for (int a = 'a'; a <= 'z'; ++a)
for (int b = a; b <= 'z'; ++b)
for (int c = b; c <= 'z'; ++c) {
for (int d = c; d <= 'y'; ++d)
printf("%c%c%c%c[%c-z]|", a, b, c, d, d);
printf("%c%c%czz", a, b, c);
if (a != 'z' || b != 'z' || c != 'z') printf("|n");
}
printf(")$/x) { print "Match!\n" } else { print "No match.\n" }}n");
return 0;
}
现在:
$ gcc r.c
$ ./a.out > foo.pl
$ cat > data.txt
aaaaa
abcde
xxyyz
ghost
chips
demos
abCde
xxyyzz
hgost
chps
^D
$ perl foo.pl < data.txt
Match!
Match!
Match!
Match!
Match!
Match!
No match.
No match.
No match.
No match.
正则表达式只有 220Kb 左右;-(