为什么我得到Regexp警告“警告:嵌套重复操作符?并且*被替换为'*'”

时间:2013-06-03 10:06:26

标签: ruby regex

我有一个用于解析挪威街道地址的正则表达式:

STREET_ADDRESS_PATTERN = <<-REGEX
    ^
    (?<street_name>[\w\D\. ]+)\s+
    (?<house_number>\d+)
    (?<entrance>[A-Z])?\s*,\s*
    (
        (?<postal_code>\d{4})\s+
        (?<city>[\w\D ]+)
    )?
    $
REGEX

它工作得更早,我不记得我是否改变了一些东西,在这种情况下我改变了什么。无论如何,现在我收到了这个警告:

  

警告:嵌套重复运算符? *被替换为'*'

比赛正在返回nil。谁能明白为什么我会收到这个警告?


注意:我目前正在使用此(假)地址来测试表达式:“Storgata 38H,0273 Oslo”。

2 个答案:

答案 0 :(得分:7)

让我们来看看你对糟糕的正则表达式引擎所做的事情:

(?<street_name>[\w\D\. ]+)\s+

问题出在角色类中:[\w\D\. ]+。以下定义来自Ruby&#39; Regexp class documentation

  • /\w/ - 单词字符([a-zA-Z0-9_])
  • /\D/ - 非数字字符([^0-9])

您告诉引擎选择:

  • abcdefghijklmnopqrstuvwxyz
  • ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • 0123456789
  • _
  • NOT 0123456789
  • 的每个字符
  • .和空格

换句话说,每个可能的角色。您也可以使用:

(?<street_name>.+)

因为那会非常贪心。此Rubular示例显示您的模式允许引擎捕获抛出的所有内容,包括几乎整个字符串Storgata 38H, 0273 Oslohttp://rubular.com/r/nMfcB0cUdu

此外,\.中的[][.]相同,因为句点中特殊使用句点作为通配符会自动转义。你不需要再次逃避它以试图使它成为文字,因为它已经是文字。

我强烈建议您使用Rubular查看正则表达式的每个部分,并尝试与其他几个可能的地址字符串进行匹配,并查看Rubular是否表示模式符合您的预期。完成后,尝试整理完整的模式。就像我一样,我认为你的小节正在互动并掩盖一些问题,这些问题会在以后再次出现。


  

我的希望是[\ w \ D]会选择除数字之外的所有单词字符......有什么办法吗?

阿。让我们再次潜入the documentation

  

POSIX括号表达式也类似于字符类。它们提供了上述的便携式替代方案,其附加好处是它们包含非ASCII字符。例如,/ \ d /仅匹配ASCII十进制数字(0-9);而/ [[:digit:]] /匹配Unicode Nd类别中的任何字符。

/[[:alnum:]]/ - Alphabetic and numeric character
/[[:alpha:]]/ - Alphabetic character
/[[:blank:]]/ - Space or tab
/[[:cntrl:]]/ - Control character
/[[:digit:]]/ - Digit
/[[:graph:]]/ - Non-blank character (excludes spaces, control characters, and similar)
/[[:lower:]]/ - Lowercase alphabetical character
/[[:print:]]/ - Like [:graph:], but includes the space character
/[[:punct:]]/ - Punctuation character
/[[:space:]]/ - Whitespace character ([:blank:], newline, carriage return, etc.)
/[[:upper:]]/ - Uppercase alphabetical
/[[:xdigit:]]/ - Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)

您想使用/[[:alpha:]]/模式。如图所示,它只能捕获一个字符,但它可以在&#34;字母&#34;的任何POSIX集合中。字符,这是你想要的范围:

[4] (pry) main: 0> 'æ, ø and å'.scan(/[[:alpha:]]/)
[
    [0] "æ",
    [1] "ø",
    [2] "a",
    [3] "n",
    [4] "d",
    [5] "å"
]

这是一个小小的调整:

[5] (pry) main: 0> 'æ, ø and å'.scan(/[[:alpha:]]+/)
[
    [0] "æ",
    [1] "ø",
    [2] "and",
    [3] "å"
]

答案 1 :(得分:1)

哦,现在我明白我做了什么。我用'替换了字符串的<<-REGEX分隔符,这意味着现在必须对表达式中的所有反斜杠进行转义。改回单一刻度可以解决问题。在sepp2k建议后,我进一步将正则表达式字符串编辑为文字:

STREET_ADDRESS_PATTERN = /
    ^
    (?<street_name>[\w\D\. ]+)\s+
    (?<house_number>\d+)
    (?<entrance>[A-Z])?\s*,\s*
    (
        (?<postal_code>\d{4})\s+
        (?<city>[\w\D ]+)
    )?
    $
/xi