8

好,朋友们。这是一个 Java 面试类型的问题,似乎难倒了一些非常聪明的人。他们实际上需要这个用于生产代码,所以它不仅仅是一个面试难题。

他们需要一个正则表达式,在 Java 中,如果字符串文字不是 3 个字母的单词 NIL,则返回true。测试需要不区分大小写,RegEx 本身必须完成所有工作。

因此,RegEx 应该拒绝NIL、nil、NiL、nIL等。

但是,它应该接受:nile、anil、will、zappa-nil-a 和空字符串。

编写一个微不足道的 RegEx 需要多少 Java 开发人员?显然很多!

4

2 回答 2

18

您可以使用负前瞻来做到这一点。

启用不区分大小写的选项:

^(?!nil$).*

.*如果您不需要在匹配中实际返回字符串,则可以在最后省略。这是一个没有不区分大小写选项的版本:

^(?![nN][iI][lL]$).*

解释:

^       # start of string anchor
(?!     # start negative lookahead (fail if...)
   nil    # literal characters 'nil'
   $      # end of string
)       # end lookahead
.*      # consume string (not necessary, but it acts more like a typical regex)

如果您希望正则表达式匹配,则在前瞻中nil\n使用\z而不是:$^(?!nil\z).*

于 2012-04-20T23:26:13.787 回答
6

这是一个真正的正则表达式,它直接指定一个有限自动机,可以一个一个地输入字符串的字符,如果字符串不是 NIL 上的变体,它将达到接受状态:

 (|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+)

这将适用于不实施环视黑客的经典正则表达式引擎,并且可以转换为极快的 DFA。

您可能必须使用^and来锚定它$,具体取决于您使用的正则表达式函数类型:(整个字符串)匹配语义或子字符串搜索语义。

例如,grep 测试:

 # rejects lines like nIl and NiL but accepts all else
 # including blank lines:

 grep -E '^(|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+)$'

这里的想法是:

  1. 所有长度为 1、2 或 4 或更多的字符串都匹配。
  2. 一个三字符的字符串匹配当且仅当:
    1. 它不以 N 或 n 开头;或者
    2. 它中间没有 I 或 i;或者
    3. 它的末尾没有 L 或 l。

NIL 和 Nil 被拒绝的原因是它们不符合所有三个规则 2.1、2.2 和 2.3。NIL 确实以 N 开头,因此它在 2.1 中失败。它中间确实有一个 I,所以它失败了 2.2,它的末尾确实有一个 L,所以它失败了 2.3。

于 2012-04-21T04:12:10.137 回答