【问题标题】:regex double white space separation problem正则表达式双空格分离问题
【发布时间】:2011-03-27 20:34:11
【问题描述】:

我想要一个正则表达式来匹配由两个或多个空格字符分隔的单词,例如

ABC  DE  FGHIJ   KLM    NO  P  QRST

注意字母之间有两个或多个空格。为此类问题编写正则表达式很容易,因为我只需要前 4 个单词,因为我们可以使用 \S+\S+? 搜索单词

但是,对于我的问题,一个单词中只能出现 1 个空格,例如

AB C  DE  FG HIJ   KLM    NO  P  QRST

这里 AB C 是一个词,而 FG HIJ 也是一个词。简而言之,我们想要隔离由两个或多个空格分隔的字符,我尝试使用这个正则表达式,

.+?  +.+?  +.+?  +.+?  +

它匹配得非常快,但是它不匹配的字符串花费了太多时间。 (这里以4个匹配为例,实际需要匹配更多)。

我需要一个更好的正则表达式来实现这一点,这样就可以避免所有的回溯。 [^ ]* 是一个正则表达式,它将匹配直到遇到空格。难道我们不能指定一个否定字符集,在出现单个空格的情况下继续匹配并在遇到 2 时中断?我尝试过使用积极的前瞻,但失败了。

非常感谢您的帮助。提前致谢。

萨德

【问题讨论】:

  • 听起来你不需要正则表达式,只需要根据分隔符" " 拆分字符串。 (
  • 我需要在开发/编译的系统中指定正则表达式,它只接受一个正则表达式字符串,它不允许任何编码或拆分。

标签: regex


【解决方案1】:

最简单的解决方案是拆分\s{2,} 以获得您想要的“单词”,但如果您坚持扫描令牌,那么您之前拥有\S+,现在拥有的是\S+(\s\S+)* .这正是它所说的:\S+,后跟零个或多个(\s\S+)。您可以使用非捕获组来提高性能,即\S+(?:\s\S+)*。如果你的风格支持它以获得额外的提升,你甚至可以使每个重复都具有所有格,即\S++(?:\s\S++)*+

这里有一个 Java sn-p 来演示:

    String text = "AB C  DE  FG HIJ   KLM    NO  P  QRST";
    Matcher m = Pattern.compile("\\S++(?:\\s\\S++)*+").matcher(text);
    while (m.find()) {
        System.out.println("[" + m.group() + "]");
    }

打印出来:

[AB C]
[DE]
[FG HIJ]
[KLM]
[NO]
[P]
[QRST]

如果这是您的要求,您当然可以只替换空格字符而不是 \s

参考文献

【讨论】:

  • FWIW,.+? +.+? +.+? +.+? + 灾难性地回溯,regular-expressions.info/catastrophic.html;不要像这样滥用.
  • 多基因润滑剂,感谢您的回复。我一直都知道这是滥用 .但我没有找到更好的解决方案。您的解决方案要好得多,因为它指定了更详细的模式。谢谢。
  • 我只是想知道我们是否需要在 WORDS 中允许 2 个空格并用 3 个或更多空格分隔正则表达式为 \S+?(\s{1,2}\S+?)*?另外,如果我需要用字母组合来分隔,例如 poly,那么正则表达式 .*?poly 会提供相同的回溯。任何 cmets 多基因润滑剂。
  • @Saad:在“单词”中最多允许 2 个空格,是的,只需使用 \s{1,2} 而不是简单的 \s。但是,您的评论中所有不情愿的修饰符都不是必需的,因为模式是如此具体,以至于只有一种方法可以匹配。我不太明白你的评论,但你可能想看看stackoverflow.com/questions/3075130/…
【解决方案2】:

如果您知道分隔符是什么 (\s\s+),则可以split 而不是 ma​​tch。 只需在两个或多个空格上拆分即可。

问候

rbo

【讨论】:

    【解决方案3】:

    我认为匹配 2 个或更多空格更简单:

    \s{2,}

    在 PHP 中,拆分看起来像这样

    $list = preg_split('/\s{2,}/', $string);

    【讨论】:

      【解决方案4】:

      如何使用这种模式:

      \s{2,}
      

      【讨论】:

        【解决方案5】:

        为什么不使用类似 \s\s+(一个空白字符,然后是一个或多个空白字符)之类的东西?

        编辑:令我震惊的是,您使用的任何语言/工具包都可能不支持直接使用正则表达式“拆分”字符串。在这种情况下,您可能希望实现该功能,而不是尝试匹配输入中的 WORDS,而是匹配 SPACES,并使用来自这些匹配项的信息 ( position, length) 来提取匹配之间的单词。在某些语言(.NET 等)中,此功能是内置的。

        【讨论】:

          【解决方案6】:

          如果您想匹配所有单词(允许连续一个空格),请尝试\S+(?:[ ]\S+)*(字符类不是必需的,可以只是空格字符,但为了清楚起见,我将其包括在内)。它指定至少需要一个非空白字符,并且一个空格后面不能跟另一个。

          您没有提及您使用的是什么语言,但这里有一个 PHP 示例:

          $string = "AB C  DE  FG HIJ   KLM    NO  P  QRST";
          $matches = array();
          preg_match_all('/\S+(?:[ ]\S+)*/', $string, $matches);
          // $matches will contain 'AB C', 'DE', 'FG HIJ', 'KLM', 'NO', 'P', 'QRST'
          

          如果要求每个单词最多一个空格,只需将末尾的* 更改为?\S+(?:[ ]\S+)?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多