正则表达式选择所有不在引号中的空格?

时间:2012-03-06 04:33:19

标签: java regex parsing

我不是很擅长RegEx,有人可以给我一个正则表达式(在Java中使用),它会选择不在两个引号之间的所有空格吗?我试图从字符串中删除所有这样的空格,所以任何解决方案都可以。

例如:

  

(这是一个测试“正则表达式的句子”)

应该成为

  

(这是“正则表达式的句子”)

7 个答案:

答案 0 :(得分:38)

这是一个有效的单一正则表达式替换:

\s+(?=([^"]*"[^"]*")*[^"]*$)

将取代:

(this is a test "sentence for the regex" foo bar)

使用:

(thisisatest"sentence for the regex"foobar)

请注意,如果引号可以转义,那么更加冗长的正则表达式就可以解决问题:

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

取代输入:

(this is a test "sentence \"for the regex" foo bar)

使用:

(thisisatest"sentence \"for the regex"foobar)

(请注意,它也适用于转义后退空间:(thisisatest"sentence \\\"for the regex"foobar)

不用说(?),这真的不应该用于执行这样的任务:它使眼睛流血,并且它在二次时间内执行其任务,同时存在简单的线性解决方案。

修改

快速演示:

String text = "(this is a test \"sentence \\\"for the regex\" foo bar)";
String regex = "\\s+(?=((\\\\[\\\\\"]|[^\\\\\"])*\"(\\\\[\\\\\"]|[^\\\\\"])*\")*(\\\\[\\\\\"]|[^\\\\\"])*$)";
System.out.println(text.replaceAll(regex, ""));

// output: (thisisatest"sentence \"for the regex"foobar)

答案 1 :(得分:10)

这是正则表达式适用于单个&双引号(假设所有字符串都正确分隔)

\s+(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)

它不会使用里面有引号的字符串。

Regular expression visualization

答案 2 :(得分:1)

这不是正则表达式所擅长的。使用正则表达式的搜索和替换函数总是有点受限,任何类型的嵌套/包含都变得困难和/或不可能。

我建议采用另一种方法:在引号字符上拆分字符串。浏览生成的字符串数组,并从每个其他子字符串中删除空格(无论是从第一个还是第二个字符串开始,取决于您是否以引号开头)。然后使用引号作为分隔符将它们连接在一起。这应该会产生你正在寻找的结果。

希望有所帮助!

PS:请注意,这不会处理嵌套字符串,但由于您无法使用ASCII double-qutoe字符创建嵌套字符串,因此我假设您不需要这种行为。

PPS:一旦你处理了你的子串,那么现在是使用正则表达式杀死这些空格的好时机 - 不用担心引号。只需记住使用/.../g修饰符来确保它是全局替换而不仅仅是第一次匹配。

答案 3 :(得分:1)

引号之外的空格组由a)的空格分隔,a)不是空格,或b)在引号内。

也许是这样的:

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

第一部分匹配一系列空格;第二部分匹配非空格(和非引号),或引号中的一些内容,重复任意次。第二部分是分隔符。

这将为结果中的每个项目提供两个组;只是忽略第二个元素。 (我们需要括号来预测,而不是在那里匹配分组。)或者,你可以说,连接所有第二个元素 - 虽然你也需要匹配第一个非空格词,或者在这个例子中,使空格可选:

StringBuffer b = new StringBuffer();
Pattern p = Pattern.compile("(\\s+)?([^ \"]+|\"[^\"]*\")*");
Matcher m = p.matcher("this is \"a test\"");
while (m.find()) {
    if (m.group(2) != null)
        b.append(m.group(2));
}
System.out.println(b.toString());

(我在Java中没有做太多正则表达式所以期待错误。)

最后,如果正则表达式是强制性的,我就是这样做的。 ; - )

除了Xavier的技术之外,你可以按照你在C中的方式进行操作:只是迭代输入字符,如果它是非空格,或者你已计算,则将每个字符串复制到新字符串到目前为止的奇数引号。

答案 4 :(得分:1)

如果只有一组引号,您可以这样做:

    String s = "(this is a test \"sentence for the regex\") a b c";

    Matcher matcher = Pattern.compile("^[^\"]+|[^\"]+$").matcher(s);
    while (matcher.find())
    {
        String group = matcher.group();
        s = s.replace(group, group.replaceAll("\\s", ""));
    }

    System.out.println(s); // (thisisatest"sentence for the regex")abc

答案 5 :(得分:0)

这不是一个确切的解决方案,但您可以通过执行以下操作来实现目标:

第1步:匹配两个部分

\\(([a-zA-Z ]\*)"([a-zA-Z ]\*)"\\)

第2步:删除空格

temp = $1 replace " " with ""

第3步:重建字符串

(temp"$2")

答案 6 :(得分:0)

我完全不知道最高投票的答案是如何起作用的,并且正则表达式是巨大的,所以我提交这个稍微简单的答案:

\s+(?=(?:'(?:\\'|[^'])+'|[^'])+$)

它(理论上)通过使用先行匹配来确保单引号(')在测试之前一直平衡到字符串的末尾,以查看空格是否是一个有效的中断位置。 / p>

这个image显示它正在执行,但确实如此,但速度很慢。正如其他答案可能已经注意到的那样,使用这样的表达式来分割潜在引用的字符串是使用锤子来移除铆钉。在我的情况下,我将这个正则表达式输入到一个程序,该程序将正则表达式拆分为(fzf)。