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

Posted

技术标签:

【中文标题】正则表达式选择所有不在引号中的空格?【英文标题】:Regular expression to select all whitespace that isn't in quotes? 【发布时间】:2012-03-23 14:10:51 【问题描述】:

我不太擅长正则表达式,有人能给我一个正则表达式(在 Java 中使用)来选择不在两个引号之间的所有空格吗?我正在尝试从字符串中删除所有此类空格,因此任何解决方案都可以这样做。

例如:

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

应该变成

(thisisatest"正则表达式的句子")

【问题讨论】:

只有 一个 组引号吗?因为这不能用于任意数量的引号(至少不能使用正则表达式)。 如果引号总是平衡的,如果嵌套引号(如果有)被转义,则可以做到。 我想知道这样一个万能的正则表达式是否存在。 【参考方案1】:

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

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

希望有帮助!

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

PPS:一旦你处理了你的子字符串,那么现在是使用正则表达式来消除这些空格的好时机——不用担心包含引号。请记住使用 /.../g 修饰符来确保它是全局替换,而不仅仅是第一个匹配项。

【讨论】:

【参考方案2】:

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

第 1 步:匹配两个段

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

第 2 步:删除空格

temp = $1 replace " " with ""

第 3 步:重建你的字符串

(temp"$2")

【讨论】:

【参考方案3】:

引号外的空格组由 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 中那样简单地执行此操作:只需遍历输入字符,然后将每个字符复制到新字符串(如果它不是空格,或者您已经计算过)到该点为止的奇数个引号。

【讨论】:

+1 是更明智的方法,但我会将其写为s=s.replaceAll("\\s+([^\\s\"]+|\"[^\"]*\"|\\z)", "$1");。空格并不是真正的可选(关键是要删除它,毕竟),所以你不需要对它进行分组。另一部分也不是可选的,你也不需要一次匹配多个,所以我去掉了*。我只需要为字符串末尾的空格添加 \z 替代项。【参考方案4】:

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

    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

【讨论】:

尝试使用字符串"this is a test \"this is a test \""。它最终会替换所有空格,因为replace() 会全局替换所有看起来正则表达式匹配的内容。【参考方案5】:

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

\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)

【讨论】:

这很好用,但对它的具体工作原理进行一些解释会有所帮助【参考方案6】:

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

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

它不适用于包含引号的字符串。

【讨论】:

我认为这是我找到的最好的一个 感谢,它可以完美地用作 sublime 的 tabalign 正则表达式

以上是关于正则表达式选择所有不在引号中的空格?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式用于在不被单引号或双引号包围时使用空格分割字符串

正则表达式捕获引号内和带/不带空格的数字

正则表达式用逗号分隔 - 不在括号或单引号内

正则表达式:如何检测空格和单引号? [关闭]

正则表达式在空格上拆分,除非在引号中

使用正则表达式转义单引号字符串中的所有双引号 [重复]