codingBat repeatEnd使用正则表达式

我正在尝试尽可能多地理解正则表达式,所以我想出了这个基于正则表达式的解决方案,以编码repeatEndrepeatEnd

给定一个字符串和一个int N,返回一个字符串,该字符串由N个字符串的最后N个字符重复组成。 您可以假设N介于0和字符串的长度之间(包括0和字符串)。

 public String repeatEnd(String str, int N) { return str.replaceAll( ".(?!.{N})(?=.*(?<=(.{N})))|." .replace("N", Integer.toString(N)), "$1" ); } 

部分说明:

  • .(?!.{N}) :断言匹配的字符是最后N个字符之一,确保后面没有N个字符。
  • (?=.*(?<=(.{N}))) :在这种情况下,使用lookforward首先一直到字符串的末尾,然后使用嵌套的lookbehind将最后N个字符捕获到\1 。 请注意,此断言始终为真。

  • |. :如果第一个断言失败(即前面至少有N个字符),那么无论如何都要匹配该字符; \1将是空的。

  • 在任何一种情况下,角色总是匹配的; 用\1替换它。

我的问题是:

  • 这种嵌套断言技术是否有效? (即在前瞻期间向后看?)
  • 有一个更简单的基于正则表达式的解决方案吗?

奖金问题

do repeatBegin (类似地定义)。

说实话,我真的遇到了麻烦!

好一个! 我没有看到显着改进该正则表达式的方法,尽管我会重构它以避免不必要地使用负逻辑:

 ".(?=.{N})|.(?=.*(?<=(.{N})))" 

这样,在你到达最后的N个字符之前,永远不会输入第二个替代方案,我认为这意味着意图更加清晰。

我从来没有见过一个参考文献说可以嵌套外观,但是像巴特一样,我不明白为什么它不会。 我有时会在lookbehinds中使用前瞻来绕过可变长度的lookbehind表达式的限制。


编辑:我刚刚意识到我可以通过将更改放在前瞻中来简化正则表达式:

 ".(?=.{N}|.*(?<=(.{N})))" 

顺便说一句,您是否考虑过使用format()来构建正则表达式而不是replace()

 return str.replaceAll( String.format(".(?=.{%1$d}|.*(?<=(.{%1$d})))", N), "$1" ); 

哇,那是一些可怕的正则表达巫术! 🙂

  • 这种嵌套断言技术是否有效? (即在前瞻期间向后看?)

是的,这在我所知道的大多数PCRE实现中都是完全有效的。

  • 有一个更简单的基于正则表达式的解决方案吗?

我没有花太多时间在上面,但我不会很快看到如何通过单一的正则表达式替换来简化或缩短。

有一个更简单的基于正则表达式的解决方案吗?

我花了一段时间,但最终我设法简化正则表达式:

 "(?=.{0,N}$(?<=(.{N}))).|." // repeatEnd -or- ".(?<=^(?=(.{N})).{0,N})|." // repeatBegin 

就像艾伦·摩尔的回答一样,这消除了否定的断言,但是甚至没有用积极的断言取而代之,所以它现在只有2个断言而不是3个断言。

我也喜欢“其他”案例只是一个简单的事实. 。 我更喜欢把我的正则表达式的大部分放在交替的“工作”方面,并保持“非工作”方面尽可能简单(通常是简单的..* )。