我正在尝试匹配文件名中不需要的区域以删除文件。
如果 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
等内容。
您可以使用
\((?!(?:[^()]*,\s*)?(?:USA|UK|Europe|Australia)\s*[,)])[^()]*\)
查看正则表达式演示
详情
\(
- 一个 (
字符(?!(?:[^()]*,\s*)?(?:USA|UK|Europe|Australia)\s*[,)])
- 负向前瞻,如果紧邻右侧有,则匹配失败
(?:[^()]*,\s*)?
- 可选序列
[^()]*
- 除 (
和 )
,
- 逗号\s*
- 0+ 个空格(?:USA|UK|Europe|Australia)
- 良好的价值观之一\s*
- 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
使用模式提取国家名称和
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);