(相当于)"字符类中的反向引用"的一般方法?

kjo*_*kjo 13 regex perl backreference character-class

在Perl的正则表达式,如表达式\1,\2等通常解释为"反向引用"到先前捕获的组,但不因此当\1,\2等字符类内出现.在后一种情况下,它\被视为转义字符(因此\1只是1等).

因此,如果(例如)想要匹配一个字符串(长度大于1),其第一个字符与其最后一个字符匹配,但不出现在字符串中的任何其他位置,则以下正则表达式不会:

/\A       # match beginning of string;
 (.)      # match and capture first character (referred to subsequently by \1);
 [^\1]*   # (WRONG) match zero or more characters different from character in \1;
 \1       # match \1;
 \z       # match the end of the string;
/sx       # s: let . match newline; x: ignore whitespace, allow comments
Run Code Online (Sandbox Code Playgroud)

工作,因为它匹配(例如)字符串'a1a2a':

  DB<1> ( 'a1a2a' =~ /\A(.)[^\1]*\1\z/ and print "fail!" ) or print "success!"
fail!
Run Code Online (Sandbox Code Playgroud)

我通常可以找到一些解决方法1,但它总是特定于问题,并且通常比我在角色类中使用反向引用时所做的更复杂.

是否有一般(希望是直截了当的)解决方法?


1例如,对于上例中的问题,我会使用类似的东西

/\A
 (.)              # match and capture first character (referred to subsequently
                  # by \1);
 (?!.*\1\.+\z)    # a negative lookahead assertion for "a suffix containing \1";
 .*               # substring not containing \1 (as guaranteed by the preceding
                  # negative lookahead assertion);
 \1\z             # match last character only if it is equal to the first one
/sx
Run Code Online (Sandbox Code Playgroud)

...在[^\1]*早期的正则表达式中,我用一些更加令人生畏的否定先行断言替换了相当简单(尽管,唉,不正确)的子表达式(?!.*\1.+\z).这个断言基本上说"如果\1出现在这一点之外的任何地方(除了在最后一个位置),就会放弃." 顺便说一下,我给出这个解决方案只是为了说明我在问题中提到的那种解决方法.我并不认为这是一个特别好的.

And*_*ark 12

这可以通过重复组中的负前瞻来实现:

/\A         # match beginning of string;
 (.)        # match and capture first character (referred to subsequently by \1);
 ((?!\1).)* # match zero or more characters different from character in \1;
 \1         # match \1;
 \z         # match the end of the string;
/sx
Run Code Online (Sandbox Code Playgroud)

即使该组包含多个字符,也可以使用此模式.