提问人:Evgeniy 提问时间:5/8/2022 最后编辑:Evgeniy 更新时间:5/9/2022 访问量:178
如果对于字符串中的每个“*”(星号),如果星号之前和之后都有字符,则返回 true
Returns true if for every '*' (star) in the string, if there are chars both immediately before and after the star, they are the same
问:
此任务是在 Codingbat 上制定的。(https://codingbat.com/prob/p194491):
如果对于字符串中的每个“*”(星号),如果星号之前和之后都有字符,则返回 true,它们相同。
sameStarChar("xy*yzz") → true
sameStarChar("xy*zzz") → false
sameStarChar("*xa*az") → true
我怎样才能修复我的解决方案,以便使用正则表达式解决此任务?
我的尝试:
public boolean sameStarChar(String str) {
return str.matches(".*([*])*.*");
}
我的解决方案对超过一半的测试是正确的,但并非对所有测试都是正确的。
答:
这是可以做到的,但它非常复杂。你的正则表达式只是扫描“任何东西,然后是任意数量的星星,然后是任何东西——它们与所有东西都匹配。您的代码实际上返回了所有可以想象的字符串。true
你的方法有问题。尝试积极匹配是相当复杂的。问题是在问否定的:“这个结构是无效的;任何没有无效构造的字符串都是有效的“,这就是它归结为,无效构造是:”A*B“,其中 A 和 B 不相同。毕竟,是有效的(示例 3)。大概也是有效的(第一颗和最后一颗星星不是问题,因为它们两边都没有字符,中间的星星很好,因为每边的字符都是相同的)。*a
***
因此,您想要的是编写一个查找无效构造的正则表达式,并返回逆向结构。
要找到无效的结构,你需要一个叫做反向引用的东西:你想搜索一个东西,然后引用它。
".\*."
- 我们从这里开始:一个角色、一个明星和一个角色。但是现在我们需要第二个字符(第二个实际上是:第一个字符以外的东西)。毕竟,也会匹配,这是一个有效的结构,所以我们不希望它匹配。.
".\*."
"A*A"
输入 backrefs。 在正则表达式中,会创建一个“组”——你以后可以参考这个东西。 是一个 backref - 它是“与第一组括号匹配的任何内容”。()
\1
但我们需要更多——我们需要否定:如果不是这样,就匹配。在 chargroups 中,有 - 表示:“任何不是'f'或'o'的字符”。但 backref 不是字符组。^
[^fo]
根据这个支持我的 SO 问题,唯一的方法是消极的展望。Lookahead 是一种你实际上并不匹配字符的东西,你只是检查它们是否匹配,如果匹配,匹配失败。它。。复杂。在网络上搜索解释“积极展望”和“消极展望”的教程。
因此:
Pattern p = Pattern.compile("(.)\\*(?!\\1|$)");
return !p.matcher(str).find();
这里正在发生各种各样的事情:
(?!X)
是负面的展望。\1|$
表示:“组 1”或“字符串末尾”。假设我们的输入包含 ,那么该星号之后的下一件事必须是 X 或字符串的末尾 - 如果是其他任何东西,我们应该返回 false。X*
- 我们不想匹配整个字符串。我们只想问:“无效构造”在这个字符串的任何地方吗?- 因此,不是 .
find()
matches()
需要明确的是,为此使用正则表达式可能是一个坏主意。当然,代码会非常短,但它并不完全可读,是吗。
如果没有正则表达式,则更容易遵循:
for (int i = 1; i < str.length() -1; i++) {
if (str.charAt(i) != '*') continue;
if (str.charAt(i - 1) != str.charAt(i + 1)) return false;
}
return true;
我强烈更喜欢上述内容,而不是一个不容易显示它实际完成什么的正则表达式,而且这个正则表达式肯定不能仅仅通过查看它来理解它的作用。
你可以使用
public boolean sameStarChar(String str) {
return str.matches("^(?!.*(.)\\*(?!\\1|$)).*");
}
细节:
^
- 字符串的开头(?!.*(.)\*(?!\1|$))
- 如果存在,则无法匹配的负面展望.*
- 除换行符以外的任何零个或多个字符,尽可能多(.)
- 组 1 ():除换行符以外的任何一个字符\1
\*
-星号(?!\1|$)
- 不紧跟与组 2 或字符串末尾相同的值
.*
- 字符串的其余部分被消耗掉(因为需要完整的字符串匹配)。.matches
评论
^
- 字符串的开头是多余的,因为正如您所说,需要整个字符串?matches()
^
下一个:编码蝙蝠计数YZ
评论
"a***b"
true
false
*xa*az
*xa
***