基于空格和java中匹配引号的正则表达式拆分字符串

时间:2014-03-14 21:47:00

标签: java regex preg-match string-split

我有一个字符串,我需要根据空格和完全匹配的引号进行拆分。

如果

string = "It is fun \"to write\" regular\"expression"

分裂后,我希望结果为:

乐趣

"写"

定期

"表达

我接近这样做的正则表达式是:

STRING_SPLIT_REGEXP = "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"

提前感谢您的回答。

3 个答案:

答案 0 :(得分:2)

您似乎只使用了来自this answer的正则表达式,但正如您所看到的那样,它不使用split类中的find而是Matcher方法。此答案还会处理',您的输入显示没有任何迹象。

因此,您可以通过删除处理'的部件来改进此正则表达式,这将使其看起来像

[^\\s\"]+|\"([^\"]*)\"

此外,由于您希望将"作为令牌的一部分包含在内,因此您无需将"之间的匹配放在单独的组中,因此请删除\"([^\"]*)\"部分中的括号

[^\\s\"]+|\"[^\"]*\"

现在您需要做的就是添加不会关闭"的情况,但您将获得字符串结尾。所以将此正则表达式更改为

[^\\s\"]+|\"[^\"]*(\"|$)

在此之后你可以使用匹配器,find所有存储令牌,让我们在List中说。

示例:

String data = "It is fun \"to write\" regular\"expression";
List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"]+|\"[^\"]*(\"|$)");
Matcher regexMatcher = regex.matcher(data);
while (regexMatcher.find()) {
    System.out.println(regexMatcher.group());
    matchList.add(regexMatcher.group());
}

输出:

It
is
fun
"to write"
regular
"expression

处理此数据的更复杂表达式可能看起来像

String data = "It is fun \"to write\" regular \"expression";
for(String s : data.split("(?<!\\G)(?<=\\G[^\"]*(\"[^\"]{0,100000}\")?[^\"]*)((?<=\"(?!\\s))|\\s+|(?=\"))"))
    System.out.println(s);

但是这种方法过于复杂,然后编写自己的解析器。


这样的解析器可能看起来像

public static List<String> parse(String data) {
    List<String> tokens = new ArrayList<String>();
    StringBuilder sb = new StringBuilder();
    boolean insideQuote = false;
    char previous = '\0';

    for (char ch : data.toCharArray()) {
        if (ch == ' ' && !insideQuote) {
            if (sb.length() > 0 && previous != '"')
                addTokenAndResetBuilder(sb, tokens);
        } else if (ch == '"') {
            if (insideQuote) {
                sb.append(ch);
                addTokenAndResetBuilder(sb, tokens);
            } else {
                addTokenAndResetBuilder(sb, tokens);
                sb.append(ch);
            }
            insideQuote = !insideQuote;
        } else {
            sb.append(ch);
        }
        previous = ch;
    }
    addTokenAndResetBuilder(sb, tokens);

    return tokens;
}

private static void addTokenAndResetBuilder(StringBuilder sb, List<String> list) {
    if (sb.length() > 0) {
        list.add(sb.toString());
        sb.delete(0, sb.length());
    }
}

用法

String data = "It is fun \"to write\" regular\"expression\"xxx\"yyy";
for (String s : parse(data))
    System.out.println(s);

答案 1 :(得分:1)

这里遇到正则表达式的基本限制。一般来说,他们无法检测递归,深度等。

所以在你的字符串中:

"It is fun \"to write\" regular\"expression"

towrite之间的空格以及\"regular之间的空格都在引号内。正则表达式无法计算&#34;引用数量灵活,并根据它采取行动。

您需要为此编写自己的字符串解析器(或使用现有的字符串解析器)。但正则表达式无法处理它。

答案 2 :(得分:1)

诀窍是使用灵活的前瞻来断言:

  • 如果输入中有偶数引号,则空格后面应该有一个偶数,因为奇数数字表示空间 引用
  • 如果输入中有奇数引号,则空格后面应该有一个奇数数字,因为偶数数字意味着空间 引号

我把它弄成了一行,但它是一个巨大的:

String[] parts = str.split("(\\s+|(?<!\\s)(?=\"))(?=(([^\"]*\"){2})*[^\"]*"
            + (str.matches("(([^\"]*\"){2})*[^\"]*") ? "" : "\"[^\"]*") + "$)");

这正确地将示例字符串拆分为带有或不带的尾随引号(无论尾部术语是否包含空格)。