我在 Java 中定义带有负向前瞻的正则表达式时遇到问题。
给定以下字符串:
今天[#[#item#] |元素#]已发货,所以[#it is|它们#]消失了。
我正在尝试根据某个值将此字符串转换为以下形式之一(是的,这是区分单数和复数形式的一种方法):
今天 [#item#] 已发货,因此已消失。
或 今天商品已发货,因此已消失
。
我正在尝试使用 Java 中的正则表达式来匹配此模式并实现此转换:
public String convert(String text, boolean isSingular) {
Pattern spPattern = Pattern.compile("\\[#.*?\\|.*?#\\]");
Matcher matcher = spPattern.matcher(text);
while (matcher.find()) {
int start = matcher.start()+2;
int end = matcher.end()-2;
int indexOfPipe = text.indexOf("|", start);
String replacement = (isSingular) ? text.substring(start, indexOfPipe) : text.substring(indexOfPipe+1, end);
text = matcher.replaceFirst(replacement);
matcher = spPattern.matcher(text);
}
}
对于单数形式:在 while
第一次迭代之后,text
是 今天 [#item#] 已发货,所以 [#it is|they are#] 消失了。
,这是可以的。然而,在第二次迭代中,Matcher
与已发货的组 [#item#] 相匹配,因此 [#it is|they are#]
,而它应该是 [#it is|they are#]
。我很确定我需要某种消极的前瞻。
我已经尝试过以下模式,但它似乎没有做任何事情:
(\\[#.*?\\|.*?#\\])(?!\\[#[^\\|]*?#\\])
(“尝试匹配 [# 和 #] 之间的所有内容,接受那些标签之间不包含 | 的情况”)
我错过了什么?
最佳答案
简介
您遇到的问题是因为您的第一个替换正在生成今天 [#item#] 已发货,因此 [#it is|they are#] 消失了。
并且您的正则表达式匹配 [#item#] 已发货,因此 [#it is|they are#]
。然后,您的正则表达式会错误地替换该字符串。
解决这个问题的真正方法是创建一个解析器,但是如果函数以递归方式运行正则表达式,则可以使用正则表达式(这有点要感谢while
循环);因此,这个答案也适用于 [#[#a|b#]|b#]
之类的东西,但请注意,任何进一步的嵌套都将失败(如果它嵌套在单数一侧)。
代码
\[#((?:\[#.*?#]|(?!#])[^|])*?)\|((?:\[#.*?#]|(?!#])[^|])*?)#]
用法
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "Today [#[#item#] was|the items were#] shipped so [#it is|they are#] gone.";
System.out.println(convert(s, true));
System.out.println(convert(s, false));
}
public static String convert(String text, boolean isSingular) {
Pattern spPattern = Pattern.compile("\\[#((?:\\[#.*?#]|(?!#])[^|])*?)\\|((?:\\[#.*?#]|(?!#])[^|])*?)#]");
Matcher matcher = spPattern.matcher(text);
while (matcher.find()) {
String replacement = isSingular ? matcher.group(1) : matcher.group(2);
text = matcher.replaceFirst(replacement);
matcher = spPattern.matcher(text);
}
return text;
}
}
<小时/>
说明
\[#
字面匹配[#
((?:\[#.*?#]|(?!#])[^|])*?)
将以下内容捕获到捕获组 1 中(?:\[#.*?#]|(?!#])[^|])*?
匹配以下任意次数,但尽可能少\[#.*?#]
匹配以下内容\[#
字面匹配[#
.*?
匹配任何字符任意次数,但尽可能少#]
按字面意思匹配
(?!#])[^|]
匹配以下内容(?!#])
负向前瞻确保后面的内容与字面上的#]
不匹配[^|]
匹配除|
之外的任何内容
\|
按字面意思匹配|
((?:\[#.*?#]|(?!#])[^|])*?)
将以下内容捕获到捕获组 2 中- 请参阅捕获组 1 下的说明(与捕获组 1 相同)
#]
字面匹配
关于java - 正则表达式中的负向前瞻匹配所有接受特定字符的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47910210/