假设有下面一段文字:
A: "Do you want tickets for tonight?"
B: "What's the movie tonight?"
A: "It's \"The Batman\"."
用 Java 字符串把这段文字写出来就是:
String dialogue =
"A: \"Do you want tickets for tonight?\" " +
"B: \"What's the movie tonight?\" " +
"A: \"It's \\\"The Batman\\\".\""
接下来的任务是用 Java 正则表达式从 dialogue 中提取出三句对话的内容,即需要输出如下内容:
>> Do you want tickets for tonight?
>> What's the movie tonight?
>> It's "The Batman".
咱们先写出代码框架:
Pattern pattern = Pattern.compile("");
Matcher m = pattern.matcher(dialogue);
while (m.find()) {
String var = str.substring(m.start(), m.end());
System.out.print(">> ");
System.out.println(var.replaceAll("\\\\\"","\"").replaceAll("^\"|\"$", ""));
}
然后就是写最关键的正则表达式了。如果只是简单地查找两个双引号之间的内容,并不能输出想要的结果:
Pattern pattern = Pattern.compile("\"(.*)\"");
....
输出:
>> Do you want tickets for tonight?" B: "What's the movie tonight?" A: "It's \"The Batman\".
正确的写法是:
Pattern pattern = Pattern.compile("\"([^\\\\\"]*(\\\\.)*)*\"");
这个看起来真头大,下面详细解释一下。
为了方便理解,首先去掉 Java 字符串的转义字符,就变成了下面的样子:
"([^\\"]*(\\.)*)*"
各个部分逐一解释如下:
" | 匹配开头的双引号 | |
([^\\"]*(\\.)*)* | 对 [^\\"]*(\\.)* 循环若干次,可以是0次。在正则表达式中,两个反斜杠(\\)表示一个实际的反斜杠字符(\) | |
[^\\"]* | 排除单独出现的反斜杠(\)和双引号(")。这个的效果是每当遇到单独的双引号,说明这个子字符串已经结束了,要停止继续往后匹配 | |
(\\.)* | 允许由反斜杠(\)转义后任意字符留在子字符串中。在这里的作用是不把 \" 看作两个单独的字符,而是看做一个被转义了的双引号 | |
" | 匹配结尾的双引号 |