【问题标题】:Regex optional non-capturing groups正则表达式可选的非捕获组
【发布时间】:2017-04-13 03:22:44
【问题描述】:

我是一个正则表达式菜鸟,花了几个小时试图解决这个难题。 我想我必须使用某种可选的非捕获组或交替。

我要匹配以下字符串:

  1. Neuer Film a von 1000

  2. Neuer Film a von 1000 mit b

  3. Neuer Film a von 1000 mit b und c

  4. Neuer Film a von 1000 mit b und c und d

  5. Neuer Film a mit b

  6. Neuer Film a mit bund c

  7. Neuer Film a mit b und c und d

我的正则表达式如下所示:

var regex = /(?:[nN]euer [Ff]ilm\s?)(.*)(?:[vV]on).(\d{4}).(?:[Mm]it)(.*)(?:[uU]nd)(.*)/g;

问题是它只匹配字符串 3 和 4。它不匹配最后两个“und”,而是将其打包在第 3 组而不是第 4 组中。

有人可以帮我解决一下我的正则表达式吗(这根本不是用户友好的;)

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    你确实需要使用非捕获可选组(如(?:...)?),但除此之外,你还需要anchors^匹配开头字符串和$ 匹配字符串结尾)和惰性点匹配模式.*?,尽可能少地匹配任何字符)。

    你可以使用

    /^[nN]euer [Ff]ilm\s*(.*?)(?:\s*[vV]on\s+(\d{4}))?(?:\s+[Mm]it\s*(.*?)(?:\s*[uU]nd\s*(.*))?)?$/
    

    请参阅regex demo。在演示中,/gm 修饰符是必需的,因为输入是多行字符串。

    模式详情

    • ^ - 字符串锚的开始
    • [nN]euer [Ff]ilm - Neuer film / Neuer Film / neuer Film
    • \s* - 零个或多个空格
    • (.*?) - 第 1 组:除换行符之外的任何 0+ 个字符,尽可能少(即,直到 最左边 出现后续子模式)
    • (?:\s*[vV]on\s+(\d{4}))? - 1 或 0 次出现:
      • \s* - 0+ 个空格
      • [vV]on - vonVon
      • \s+ - 1+ 个空格
      • (\d{4}) - 第 2 组:4 位数
    • (?:\s+[Mm]it\s*(.*?)(?:\s*[uU]nd\s*(.*))?)? - 一个可选的非捕获组,匹配 1 次或 0 次出现:
      • \s+ - 1+ 个空格
      • [Mm]it - Mitmit
      • \s* - 0+ 个空格
      • (.*?) - 第 3 组匹配除换行符以外的任何 0+ 字符,尽可能少
      • (?:\s*[uU]nd\s*(.*))? - 可选的非捕获组匹配
        • \s*[uU]nd\s* - undUnd 包含 0+ 个空格
        • (.*) - 第 4 组匹配除换行符以外的任何 0+ 字符,尽可能多
    • $ - 字符串结束。

    var strs = ['Neuer Film a von 1000','Neuer Film a von 1000 mit b','Neuer Film a von 1000 mit b und c','Neuer Film a von 1000 mit b und c und d','Neuer Film a mit b','Neuer Film a mit b und c','Neuer Film a mit b und c und d'];
    var rx = /^[nN]euer [Ff]ilm\s*(.*?)(?:\s*[vV]on\s+(\d{4}))?(?:\s+[Mm]it\s*(.*?)(?:\s*[uU]nd\s*(.*))?)?$/;
    for (var s of strs) {
       var m = rx.exec(s);
       if (m) {
         console.log('-- ' + s + ' ---');
         console.log('Group 1: ' + m[1]);
         if (m[2]) console.log('Group 2: ' + m[2]);
         if (m[3]) console.log('Group 3: ' + m[3]);
         if (m[4]) console.log('Group 4: ' + m[4]);
       }
       
    }

    【讨论】:

    • 非捕获组仍然使用文本,它们不是像lookbehinds或lookaheads这样的零宽度断言。
    • 非常感谢您的回答。我从没想过我必须像您描述的那样使用可选的非捕获组,因为我仍然希望它们出现在匹配组中(认为(...)? 就足够了)。而且我也从来没有想过这种懒惰的点匹配。但是我仍然不明白为什么第一个“und”没有被捕获而后面的“und”被捕获,尽管它们在一个非捕获组中?
    • .*? 匹配尽可能少的字符,因此,正则表达式会到达und最左出现(与\s*[uU]nd\s* 匹配,未捕获) )。请注意,惰性模式不匹配 2 个字符串之间的 shortest 子字符串(如某些 SO 答案中所述),它们仅匹配后续子模式的最左侧出现。
    • 我添加了细节并稍微缩短了正则表达式,因为一些非捕获组(未量化,也不包含交替)是多余的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多