1

这是一个填字游戏。例子:

  • 解决方案是一个以“r”开头并以“r”结尾的 6 个字母的单词
  • 因此模式是“r....r”
  • 未知的 4 个字母必须从字母“a”、“e”、“i”和“p”的池中抽取
  • 每个字母必须只使用一次
  • 我们有大量候选 6 字母单词

解决方案:“剑杆”或“修复”。

过滤模式“r....r”是微不足道的,但是在“未知”插槽中找到也有 [aeip] 的单词超出了我的范围。

这个问题适合正则表达式,还是必须通过详尽的方法来完成?

4

7 回答 7

4

尝试这个:

r(?:(?!\1)a()|(?!\2)e()|(?!\3)i()|(?!\4)p()){4}r

...或者更具可读性:

r
(?:
  (?!\1) a () |
  (?!\2) e () |
  (?!\3) i () |
  (?!\4) p ()
){4}
r

空组用作复选标记,在每个字母被消耗时打勾。例如,如果要匹配的单词是repair,则 thee将是此构造匹配的第一个字母。e如果正则表达式稍后尝试匹配另一个,则该替代将不匹配它。负前瞻(?!\2)将失败,因为第 2 组已经参加了比赛,更不用说它没有消耗任何东西。

真正酷的是它同样适用于包含重复字母的字符串。举个redeem例子:

r
(?:
  (?!\1) e () |
  (?!\2) e () |
  (?!\3) e () |
  (?!\4) d ()
){4}
m

在第一个e被消耗后,第一个替代品被有效地禁用,所以第二个替代品取而代之。等等...

不幸的是,这种技术不适用于所有正则表达式。一方面,他们并不都将空/失败的组捕获视为相同的。ECMAScript 规范明确指出,对非参与组的引用应该总是成功的。

正则表达式风格还必须支持前向引用——即出现在它们在正则表达式中引用的组之前的反向引用。( ref ) 据我所知,它应该可以在 .NET、Java、Perl、PCRE 和 Ruby 中工作。

于 2013-04-17T19:55:35.657 回答
0

假设您的意思是未知字母必须在 [aeip] 之间,那么合适的正则表达式可能是:

/r[aeip]{4,4}r/
于 2013-04-17T15:07:11.487 回答
0

由于 sed 多正则表达式操作,未完全正则表达式

sed -n -e '/^r[aiep]\{4,\}r$/{/\([aiep]\).*\1/!p;}' YourFile

取组中的模式 4 字母aeipr只保留在子组中没有找到字母的行两次。

于 2014-06-11T08:26:38.223 回答
0

用于比较字符串的前端语言是什么,是 java、.net ...

这是使用 java 的示例/伪代码

    String mandateLetters = "aeio"
    String regPattern = "\\br["+mandateLetters+"]*r$";  // or if for specific length \\br[+mandateLetters+]{4}r$

    Pattern pattern = Pattern.compile(regPattern);
    Matcher matcher = pattern.matcher("is this repair ");

    matcher.find();
于 2013-04-17T15:10:49.487 回答
0

为什么不替换每个“。” 在您的原始模式中使用“[aeip]”?

你会得到一个正则表达式 string r[aeip][aeip][aeip][aeip]r

这当然可以缩短为r[aeip]{4,4}r,但在一般情况下实现起来会很痛苦,并且可能不会改进代码。

这并没有解决重复字母使用的问题。如果我正在编码它,我会在正则表达式之外的代码中处理它 - 主要是因为正则表达式会变得比我想要处理的更复杂。

于 2013-04-17T15:16:38.887 回答
0

所以“只有一次”部分是关键。列出所有排列显然是不可行的。如果您的语言/环境支持前瞻和反向引用,您可以让自己更轻松一些:

r(?=[aeip]{4,4})(.)(?!\1)(.)(?!\1|\2)(.)(?!\1|\2|\3).r

仍然很丑陋,但它是这样工作的:

r     # match an r
(?=   # positive lookahead (doesn't advance position of "cursor" in input string)
  [aeip]{4,4}
)     # make sure that there are the four desired character ahead
(.)   # match any character and capture it in group 1
(?!\1)# make sure that the next character is NOT the same as the previous one
(.)   # match any character and capture it in group 2
(?!\1|\2)
      # make sure that the next character is neither the first nor the second
(.)   # match any character and capture it in group 3
(?!\1|\2|\3)
      # same thing again for all three characters
.     # match another arbitrary character
r     # match an r

工作演示。

这既不优雅也不可扩展。因此,您可能只想使用r([aiep]{4,4})r(捕获四个关键字母)并确保没有正则表达式的附加条件。

编辑:事实上,如果你只是想确保你有 4 个不相同的字符,上述模式才是真正有用和必要的。对于您的具体情况,再次使用前瞻,有更简单(尽管更长)的解决方案:

r(?=[^a]*a[^a]*r)(?=[^e]*e[^e]*r)(?=[^i]*i[^i]*r)(?=[^p]*p[^p]*r)[aeip]{4,4}r

解释:

r       # match an r
(?=     # lookahead: ensure that there is exactly one a until the next r
  [^a]* # match an arbitrary amount of non-a characters
  a     # match one a
  [^a]* # match an arbitrary amount of non-a characters
  r     # match the final r
)       # end of lookahead
(?=[^e]*e[^e]*r)  # ensure that there is exactly one e until the next r
(?=[^i]*i[^i]*r)  # ensure that there is exactly one i until the next r
(?=[^p]*p[^p]*r)  # ensure that there is exactly one p until the next r
[aeip]{4,4}r      # actually match the rest to include it in the result

工作演示。

对于r....m的池deee,可以将其调整为:

r(?=[^d]*d[^d]*m)(?=[^e]*(?:e[^e])*{3,3}m)[de]{4,4}m

这确保了d恰好 1 秒和 3e秒。

工作演示。

于 2013-04-17T15:18:32.777 回答
0

一个更具可扩展性的解决方案(无需为每个字母或位置编写 \1、\2、\3 等)是使用负前瞻来断言每个字符稍后不会出现:

^r(?:([aeip])(?!.*\1)){4}r$

更具可读性:

^r
(?:
  ([aeip])
  (?!.*\1)
){4}
r$

改进

这是一个快速的解决方案,适用于您给我们的情况,但这里有一些额外的限制,以获得更强大的版本:

  • 如果“字母池”可能与字符串结尾共享一些字母,请在前瞻中包含模式结尾:

    ^r(?:([aeip])(?!.*\1.*\2)){4}(r$)
    

    (可能无法在所有正则表达式风格中按预期工作,在这种情况下,复制粘贴模式的结尾而不是使用\2

  • 如果某些字母不仅必须出现一次,而且必须出现不同的固定次数,请为共享此次数的所有字母添加单独的前瞻。例如,带有一个“a”和一个“p”但两个“e”的“r....r”将被这个正则表达式匹配(但“rapper”和“repeer”不会):

    ^r(?:([ap])(?!.*\1.*\3)|([e])(?!.*\2.*\2.*\3)){4}(r$)
    

    非捕获组现在有 2 个备选方案:([ap])(?!.*\1.*\3)匹配 "a" 或 "p" 在任何地方都没有跟随,直到另一个结尾,([e])(?!.*\2.*\2.*\3)它匹配 "e" 在任何地方都没有跟随,直到其他 2 个结尾(所以它在第一个失败如果总共有 3 个,则为一个)。顺便说一句,此解决方案包括上述解决方案,但模式的结尾在这里转移到\3(另请参阅关于风味的注释)。

于 2016-08-09T11:56:01.563 回答