REGEX - 需要一种负向查找多个字符串的方法

问题描述 投票:0回答:3

我正在尝试匹配文件名中不需要的区域以删除文件。

如果 REGEX 找到“坏区域”,我希望获得任何匹配

(Brazil or Columbia)
但如果它们与同一括号中的“好区域”混合在一起,则不会
(USA, UK, Europe, Australia)

我有一个正则表达式

(?<![( ](USA)[,)])[( ](Brazil|Columbia)[,)](?![( ](USA|UK|Europe|Australia)[,)])

FIFA Soccer (USA, Brazil)      <<< DON't MATCH IF USA IS IN SAME BRACKET BEFORE
FIFA Soccer (Brazil, USA)      <<< DON't MATCH IF USA IS IN SAME BRACKET AFTER
FIFA Soccer (Brazil)           <<< MATCH
FIFA Soccer (Brazil, Ireland)  <<< MATCH
FIFA Soccer (Moon, Brazil)     <<< MATCH

到目前为止,正确的行匹配,但那是因为我有一个固定宽度的“负后视”寻找“美国”……但我也希望在我的负后视中找到“英国”“欧洲”和“澳大利亚” ,我不能这样做,因为它们必须是“固定宽度”......

FIFA Soccer (UK, Brazil) <<< ERROR - THIS ONE SHOULDN'T MATCH AND DOES
FIFA Soccer (Brazil, UK) <<< This one works (no match) because I have my lookahead set up

查看现场演示: 这里

那么有没有一种方法可以在正则表达式的开头使类似

(?<![( ](USA|UK|Europe|Australia)[,)])
的内容生效,以取消匹配
UK, Brazil
Europe, Brazil
等内容。

regex preg-match regex-lookarounds
3个回答
0
投票

您可以使用

\((?!(?:[^()]*,\s*)?(?:USA|UK|Europe|Australia)\s*[,)])[^()]*\)

查看正则表达式演示

详情

  • \(
    - 一个
    (
    字符
  • (?!(?:[^()]*,\s*)?(?:USA|UK|Europe|Australia)\s*[,)])
    - 负向前瞻,如果紧邻右侧有,则匹配失败
    • (?:[^()]*,\s*)?
      - 可选序列
      • [^()]*
        - 除
        (
        )
      • 之外的 0+ 个字符
      • ,
        - 逗号
      • \s*
        - 0+ 个空格
    • (?:USA|UK|Europe|Australia)
      - 良好的价值观之一
    • \s*
      - 0+ 个空格
    • [,)]
      -
      ,
      )
  • [^()]*
    - 除
    (
    )
  • 之外的 0 个或多个字符
  • \)
    - 一个
    )
    字符。

0
投票

您可以交替使用 PCRE 动词

(*SKIP)(*F)
来代替可变长度负向后查找来匹配和拒绝匹配:

(?:USA|UK|Europe|Australia),\h*(?:Brazil|Austria)[,)](*SKIP)(*F)|(?:Brazil|Austria)[,)](?!\h?(?:USA|UK|Europe|Australia)[,)])

更新了正则表达式演示

  • (*FAIL)
    的行为类似于失败的否定断言,是
    (?!)
  • 的同义词
  • (*SKIP)
    定义了一个点,当子模式稍后失败时,正则表达式引擎将不允许回溯到该点
  • (*SKIP)(*FAIL)
    一起提供了一个很好的限制替代方案,即在上面的正则表达式中不能有可变长度的lookbehind。

您可以在 PCRE 中使用

DEFINE
动词来避免在正则表达式中重复,如下所示:

/
(?(DEFINE) # use define to avoid repetitions
  (?<ct>USA|UK|Europe|Australia) # disallow countries
  (?<mct>Brazil|Austria) # matching countries
)
# main regex starts here
(?&ct),\h*(?&mct)[,)](*SKIP)(*F)
|
(?&mct)[,)](?!\h?(?&ct)[,)])
/x

正则表达式演示 2


0
投票

使用模式提取国家名称和

array_filter

$filenames = ['FIFA Soccer (USA, Brazil)',
              'FIFA Soccer (Brazil, USA)',
              'FIFA Soccer (Brazil)',
              'FIFA Soccer (Brazil, Ireland)',
              'FIFA Soccer (Moon, Brazil)'];

$bad = ['Brazil', 'Columbia'];
$good = ['USA', 'UK', 'Europe', 'Australia'];

$todelete = array_filter($filenames, function ($i) use ($bad, $good) {
    $countries = preg_match_all('~(?:\G(?!\A), |\()\K\pL+~', $i, $m) ? $m[0] : [];
    return array_intersect($countries, $bad) && !array_intersect($countries, $good);
});

print_r($todelete);
© www.soinside.com 2019 - 2024. All rights reserved.