7

我最近遇到了一个难题,以找到匹配的正则表达式:

由 ASCII 升序的小写英文字母组成的 5 个字符长的字符串

有效的例子包括:

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)的逻辑是捕获第一个字符 [az],将其用作第二个字符类中的反向引用,依此类推。但是,字符类中的\1, \2... 似乎指的是 1、2... 的 ASCII 值,有效地匹配任何四或五个字符的字符串。

我有两个问题:

  1. 我可以在我的字符类中使用反向引用来检查升序字符串吗?
  2. 这个难题有什么不那么棘手的解决方案吗?
4

4 回答 4

4

我将此答案发布为评论而不是答案,因为它的格式比评论更好。

与您的问题相关:

  1. 我可以在我的字符类中使用反向引用来检查升序字符串吗?

不,你不能。如果您查看backref 正则表达式部分,您将找到以下文档:

括号和反向引用不能在字符类中使用

括号不能在字符类中使用,至少不能用作元字符。当您将括号放入字符类中时,它被视为文字字符。所以正则表达式 [(a)b] 匹配 a, b, (, and )。

反向引用也不能在字符类中使用。像 (a)[\1b] 这样的正则表达式中的 \1 要么是错误,要么是不必要的转义文字 1。在 JavaScript 中,它是八进制转义。

关于你的第二个问题:

  1. 这个难题有什么不那么棘手的解决方案吗?

恕我直言,您的正则表达式非常好,您可以在开始时将其缩短一点,如下所示:

(?=^.{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

正则表达式演示

于 2017-07-14T20:05:29.010 回答
3

如果您愿意使用 Perl (!),这将起作用:

/^([a-z])((??{"[$1-z]"}))((??{"[$2-z]"}))((??{"[$3-z]"}))(??{"[$4-z]"})$/
于 2017-07-14T23:33:29.450 回答
2

由于有人使用 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
于 2017-07-15T21:03:20.483 回答
2

啊,好吧,它是一个有限集,所以你总是可以交替枚举它!这会在一点 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 左右;-)

于 2017-07-20T04:17:43.860 回答