【问题标题】:Java regex to match double quoted substringsJava正则表达式匹配双引号子字符串
【发布时间】:2017-10-10 09:06:58
【问题描述】:

我要解析以下字符串:

String text = "\"w1 w\"2\" w3 | w4 w\"5 \"w6 w7\"";
// "w1 w"2" w3 | w4 w"5 "w6 w7"

我正在使用Pattern.compile(regex).matcher(text),所以我在这里缺少的是正确的正则表达式。 规则是正则表达式必须:

  • 隔离任何单个单词
  • 任何用双引号括起来的子字符串都是匹配的
  • 必须忽略单词中的双引号(稍后我将用空格替换它们)。

所以结果匹配应该是:

  1. w1 w"2
  2. w3
  3. |
  4. w4
  5. w"5
  6. w6 w7

双引号是否包含在双引号包围的子字符串中是无关紧要的(例如 1. 可以是 w1 w"2"w1 w"2")。

我想出的是这样的:

"\"(.*)\"|(\\S+)"

我还尝试了上述正则表达式的许多不同变体(包括后向/前向),但没有一个能够给我预期的结果。

关于如何改进这一点的任何想法?

【问题讨论】:

  • 如何让一个被" " 覆盖的字符串包含多个"s?会不会直接把w1 w当成一个词,而不是w1 w"2
  • 也许我误解了你的问题,但我认为你在这里可能有一个矛盾的要求:“必须忽略单词中的双引号”。 Java 正则表达式中的一个词被定义为[A-Za-z0-9_](参见en.wikipedia.org/wiki/Regular_expression#Character_classes),所以你不能在一个词中包含"...
  • 试试String pat = "\"[^\"]*(?:\\b\"\\b[^\"]*)*\"|\\S+";
  • @procrastinator; @anothernode:您对Java正则表达式领域中单词的严格定义是正确的,我在这里的意思是单词被'“'分成两部分,它仍然应该被视为一个单一的(让我通过定义)......单词.

标签: java regex


【解决方案1】:

试试这个正则表达式:

(?:(?<=^")|(?<=\s")).*?(?="(?:\s|$))|(?![\s"])\S+

Click for Demo

解释:

  • (?:(?<=^")|(?<=\s")) - 正向向后查找以查找 " 之前的位置。此" 需要位于字符串的开头或空格之后
  • .*? - 懒惰地匹配除换行符以外的任何字符的 0+ 次出现
  • (?="(?:\s|$)) - 积极的前瞻来验证到目前为止匹配的内容后面是空格还是匹配后没有任何内容($)。
  • | - 或(以上匹配或以下匹配)
  • (?![\s"]) - 负前瞻验证该位置后面没有空格或"
  • \S+ - 匹配 1+ 个非空白字符

Java 代码(Generated from here):

Run code here to see the output

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyClass {
    public static void main(String args[]) {
    final String regex = "(?:(?<=^\")|(?<=\\s\")).*?(?=\"(?:\\s|$))|(?![\\s\"])\\S+";
    final String string = "\"w1 w\"2\" w3 | w4 w\"5 \"w6 w7\"";

    final Pattern pattern = Pattern.compile(regex);
    final Matcher matcher = pattern.matcher(string);

    while (matcher.find()) {
        System.out.println("Full match: " + matcher.group(0));
        for (int i = 1; i <= matcher.groupCount(); i++) {
            System.out.println("Group " + i + ": " + matcher.group(i));
        }
    }

    }
}

输出:

【讨论】:

  • 最后我使用了一个轻微的定制。谢谢。
【解决方案2】:

这似乎可以完成工作:

"(?:[^"]|\b"\b)+"|\S+

Debuggex Demo

Regex101 Demo


请注意,在 Java 中,因为我们在正则表达式中使用字符串文字,所以反斜杠前面需要有另一个反斜杠:

String regex = "\"(?:[^\"]|\\b\"\\b)+\"|\\S+";

【讨论】:

  • 我认为按照预期的输出 1 和 6,不需要双引号。
  • @Gurman 是的,但我无法找到忽略周围引号的解决方案。不过,这可以在第二个短语中轻松完成。
  • 仅供参考 "\"(?:[^\"]|\\b\"\\b)+\"|\\S+" 将匹配与 my suggestion 相同的字符串,但这个会慢一些。
  • @WiktorStribiżew 没错,好点。好吧,请随意添加您的答案;)您是否找到忽略周围引号的方法?
  • @sp00m 这是不可能的。只需使用一个捕获组,如果它不为空,则添加到最终的字符串列表中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2018-03-06
  • 1970-01-01
  • 2016-04-18
相关资源
最近更新 更多