正则表达式:何时匹配模式0次或多次有用?

时间:2018-07-12 08:58:46

标签: regex

我想问一些匹配0次模式的例子是否有用?

我对this问题的理解是,它还用于捕获空字符串以及> 0个出现的字符串(或字符)。有使用的实际例子,以便我可以更好地理解直觉吗?

2 个答案:

答案 0 :(得分:3)

如果您想查看所使用的*量词的真实示例。只是看看堆栈溢出!找到一个回答很多正则表达式问题的人,例如Wiktor Stribiżew,并在其答案中搜索*的用法。这是我的answer,它使用*

*的一个非常常见的用例是匹配可选的空格。通常,当您要求用户输入内容时,您希望尽可能宽松(用户可以添加任意数量的空格,或者完全不添加空格),而不是遵循非常严格的语法。

例如,电话号码。我住的地方的电话号码是8位数字,它们以4为一组进行分组。例如

1234 5678

为了尽可能宽松,可以使用这样的正则表达式:

^\s*(\d{4})\s*(\d{4})\s*$

看到使用*吗?它允许任何数量(包括0)的尾部,前导空格和中间空格。即使用户不小心在中间输入了两个空格,程序仍然可以理解它们。

正则表达式可以匹配所有这些

1234 5678
12345678
   1234 5678   
1234    5678

或者我可以更加宽容,并在各处留出空间:

^(?:\s*\d\s*){8}$

无论如何,有一天您认为不需要的事情会在您需要的时候派上用场。当我学习如何编码时,我曾经想过“这种语言功能是没有用的”,但是当我实际编写代码来解决问题时,我常常会开始使用那些我认为“无用”的功能。在适合使用*的地方,您只是没有遇到问题。

答案 1 :(得分:1)

为了扩展对{0}量词的评论... Ruby的Onigmo是功能更丰富的正则表达式引擎之一(尽管它也有缺点,尤其是在Unicode合规性AFAIK中)。非常有趣的一点是,它允许您创建子例程-基本上,以递归方式匹配已定义的命名组。反过来,这几乎可以让您创建一个解析器(尽管我仍然建议在需要解析器时使用Treetop或其他“真正的”解析器库)。

这是一个玩具示例(https://tomassetti.me/ebnf/中Tiny C语法的翻译)。 {0}用于在定义时不匹配组,仅在\g<name>构造显式调用时使用。

tiny_c_re = %r{
  (?<program> \g<statement>+){0}
  (?<statement>
    if \g<paren_expr> \g<statement> (?:else \g<statement>)? |
    while \g<paren_expr> \g<statement> |
    do \g<statement> while \g<paren_expr> ; |
    { \g<statement>* } |
    \g<expr> ; |
    ;
  ){0}
  (?<paren_expr> \( \g<expr> \) ){0}
  (?<expr>
    \g<test> |
    \g<id> = \g<expr>
  ){0}
  (?<test> \g<sum> (?: < \g<sum> )? ){0}
  (?<sum> \g<term> (?: [+-] \g<term> )? ){0}
  (?<term> \g<id> | \g<integer> | \g<paren_expr> ){0}
  (?<id> \g<string> ){0}
  (?<integer> \g<int> ){0}
  (?<string> [a-z]+ ){0}
  (?<int> [0-9]+ ){0}

  ^ \g<program> $
}x

good = <<EOF
  count = 5;
  sum = 0;
  while (0 < count) {
    sum = sum + count;
    count = count - 1;
  }
EOF
puts good.gsub(/[ \r\n\t]+/, '') =~ tiny_c_re ? "Correct" : "Syntax error"
# => Correct

bad = <<EOF
  count = 5;
  sum = 0;
  while (0 < count) {
    sum = = sum + count;
    count = count - 1;
  }
EOF
puts bad.gsub(/[ \r\n\t]+/, '') =~ tiny_c_re ? "Correct" : "Syntax error"
# => Syntax error