您可以在字符串拆分中使用零宽度匹配正则表达式吗?
Posted
技术标签:
【中文标题】您可以在字符串拆分中使用零宽度匹配正则表达式吗?【英文标题】:Can you use zero-width matching regex in String split? 【发布时间】:2011-01-25 06:50:36 【问题描述】:System.out.println(
Arrays.deepToString(
"abc<def>ghi".split("(?:<)|(?:>)")
)
);
这打印出[abc, def, ghi]
,就好像我在"<|>"
上分裂了一样。我希望它打印[abc, <def>, ghi]
。有没有办法使用一些正则表达式来完成我想要的?
也许是一个更简单的例子:
System.out.println(
Arrays.deepToString(
"Hello! Oh my!! Good bye!!".split("(?:!+)")
)
);
这将打印[Hello, Oh my, Good bye]
。我希望它打印[Hello!, Oh my!!, Good bye!!]
。
`.
【问题讨论】:
重复***.com/questions/275768/… 【参考方案1】:你需要看看零宽度匹配结构:
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?<!X) X, via zero-width negative lookbehind
【讨论】:
是的,我误解了(?:
...)
的用途。【参考方案2】:
您可以使用\b
(字边界)作为要查找的内容,因为它是零宽度,并将其用作查找<
和>
的锚。
String s = "abc<def>ghi";
String[] bits = s.split("(?<=>)\\b|\\b(?=<)");
for (String bit : bits)
System.out.println(bit);
输出:
abc
<def>
ghi
现在这不是一个通用的解决方案。您可能需要为此编写一个自定义拆分方法。
您的第二个示例表明您所追求的并不是真正的split()
,而是一个正则表达式匹配循环。例如:
String s = "Hello! Oh my!! Good bye!!";
Pattern p = Pattern.compile("(.*?!+)\\s*");
Matcher m = p.matcher(s);
while (m.find())
System.out.println("[" + m.group(1) + "]");
输出:
[Hello!]
[Oh my!!]
[Good bye!!]
【讨论】:
您能否对我的回答发表评论,看看有什么问题吗?谢谢。【参考方案3】:感谢 Cine 提供的信息,我认为这些是我正在寻找的答案:
System.out.println(
Arrays.deepToString(
"abc<def>ghi<x><x>".split("(?=<)|(?<=>)")
)
); // [abc, <def>, ghi, <x>, <x>]
System.out.println(
Arrays.deepToString(
"Hello! Oh my!! Good bye!! IT WORKS!!!".split("(?<=!++)")
)
); // [Hello!, Oh my!!, Good bye!!, IT WORKS!!!]
现在,第二个是通过尝试所有不同的量词诚实地发现的。贪婪和不情愿都不会起作用,但占有欲会起作用。
我还是不知道为什么。
【讨论】:
你的第二个例子不应该工作。 :-/ 它应该抛出 PatternSyntaxException,因为后视没有明显的最大长度。您的正则表达式编译是一个错误;它有效令人难以置信——而且不值得依赖。这是您应该使用的:(?<=!)(?!!)
。这适用于任何支持前瞻和后瞻的正则表达式风格。
该错误已被报告,如果这就是您的意思。我建议你在任何情况下都不要养成在lookbehinds中使用可变宽度表达式的习惯;很少有正则表达式支持该功能,而且通常有更好的方法。以上是关于您可以在字符串拆分中使用零宽度匹配正则表达式吗?的主要内容,如果未能解决你的问题,请参考以下文章