codingBat repeatEnd使用正则表达式
我正在尝试尽可能多地理解正则表达式,所以我想出了这个基于正则表达式的解决方案,以编码repeatEnd
: repeatEnd
:
给定一个字符串和一个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个断言。
我也喜欢“其他”案例只是一个简单的事实.
。 我更喜欢把我的正则表达式的大部分放在交替的“工作”方面,并保持“非工作”方面尽可能简单(通常是简单的.
或.*
)。