尝试提取用双括号括起来的字符串。例如[[这是一个标记]]应该匹配。为了使事情更加优雅,应该有一个转义序列,以便像[[这个转义的令牌\]]这样的双括号项目不会匹配。
带有“group 1”的模式[^\\\\]([\\[]{2}.+[^\\\\][\\]]{2})
来提取令牌很接近,但有些情况下它不起作用。问题似乎是第一个“不”语句被评估为“除了反斜杠之外的任何东西”。问题是,“任何事情”都不包括“没有”。那么,什么会使这个模式匹配“除了反斜杠之外没有任何字符”?
这是一个显示所需行为的单元测试:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import junit.framework.TestCase;
public class RegexSpike extends TestCase {
private String regex;
private Pattern pattern;
private Matcher matcher;
@Override
protected void setUp() throws Exception {
super.setUp();
regex = "[^\\\\]([\\[]{2}.+[^\\\\][\\]]{2})";
pattern = Pattern.compile(regex);
}
private String runRegex(String testString) {
matcher = pattern.matcher(testString);
return matcher.find() ? matcher.group(1) : "NOT FOUND";
}
public void testBeginsWithTag_Passes() {
assertEquals("[[should work]]", runRegex("[[should work]]"));
}
public void testBeginsWithSpaces_Passes() {
assertEquals("[[should work]]", runRegex(" [[should work]]"));
}
public void testBeginsWithChars_Passes() {
assertEquals("[[should work]]", runRegex("anything here[[should
work]]"));
}
public void testEndsWithChars_Passes() {
assertEquals("[[should work]]", runRegex("[[should
work]]with anything here"));
}
public void testBeginsAndEndsWithChars_Passes() {
assertEquals("[[should work]]", runRegex("anything here[[should
work]]and anything here"));
}
public void testFirstBracketsEscaped_Fails() {
assertEquals("NOT FOUND", runRegex("\\[[should NOT work]]"));
}
public void testSingleBrackets_Fails() {
assertEquals("NOT FOUND", runRegex("[should NOT work]"));
}
public void testSecondBracketsEscaped_Fails() {
assertEquals("NOT FOUND", runRegex("[[should NOT work\\]]"));
}
}
答案 0 :(得分:3)
您只需使用(^|[^\\])
, 匹配字符串的开头(假设您在正则表达式上设置了MULTILINE
模式)或一个不是反斜杠的单个字符(包括空格,换行符等)。
您还希望将.+
替换为.+?
,否则"[[one]] and [[two]]"
之类的字符串将被视为单个匹配,其中"one]] and [[two"
被视为在括号之间。
第三点是,您不必在\[
的字符类中包装单个字符(甚至包括\]
或[]
等转义字符)。
这样就可以制作以下正则表达式(原谅我为了清晰起见而删除了双重转义):
(^|[^\\])(\[{2}.+?[^\\]\]{2})
(另请注意,您无法使用正则表达式转义转义字符。[
之前的两个斜杠不会被解析为单个(转义)斜杠,但会指示单个(未转义)斜杠和一个转义括号。)
答案 1 :(得分:1)
你想要一个“零宽度负向后观断言”,即(?<!expr)
。尝试:
(?<!\\\\)([\\[]{2}.+[^\\\\][\\]]{2})
实际上,这可以简化,并通过删除一些不必要的括号,并为结束括号添加负面的后视,使其更加通用。 (如果您在字符串中间有一个转义括号,例如[[text\]]moretext]]
),您的版本也会失败。
(?<!\\\\)(\\[{2}.*?(?<!\\\\)\\]{2})
答案 2 :(得分:1)
这个字符串会发生什么? (实际字符串内容,而不是Java文字。)
foo\\[[blah]]bar
我要问的是你是否支持转义反斜杠。如果你是,那么后视将不起作用。你不必寻找单个反斜杠,而是要检查奇数但未知数量,而Java lookbehinds不能像这样开放式。另外,如果转义括号里面的一个令牌 - 这有效吗?
foo[[blah\]]]bar
在任何情况下,我建议您从另一个方向出现反斜杠问题:将第一个括号前面的任意数量的转义字符(即反斜杠加上任何内容)作为令牌的一部分进行匹配。在令牌内,匹配除方括号或反斜杠之外的任意数量的字符,或任意数量的转义字符。这是实际的正则表达式:
(?<!\\)(?:\\.)*+\[\[((?:[^\[\]\\]++|\\.)*+)\]\]
...这里它是一个Java字符串文字:
"(?<!\\\\)(?:\\\\.)*+\\[\\[((?:[^\\[\\]\\\\]++|\\\\.)*+)\\]\\]"