Preg_match 是 "ignoring" 捕获组定界符

Preg_match is "ignoring" a capture group delimiter

我们的数据库中存储了数千个结构化文件名,不幸的是,有数百个文件名已被手动更改为不符合我们命名约定的名称。使用正则表达式,我试图匹配正确的文件名以识别所有命名错误的文件。 这些文件都与会议议程相关,并在名称中使用日期、会议类型、议程项目#和描述。

我们的命名约定是 yyyymmdd_aa[_bbb]_ccccc.pdf 其中:

示例文件名:

   20200225_RM_agenda.pdf
   20200225_RM_2_memo.pdf
   20200225_SS1_3c_presenTATION.pdf
   20200225_CA_4d_SiGnEd.pdf
   20200225_RM_5_Order1234.pdf
   2021_02_25_EV_Notice.pdf

我用来匹配这些文件的正则表达式如下 (regex demo):

/^(\d{4}[_]?\d{2}[_]?\d{2})_(\w{2,3})_([a-z0-9]{1,3})_?(.+)?.pdf/i

问题: 一般来说,它工作正常,但如果议程编号(“bbb”)不在文件名中,则正则表达式捕获并 returns 描述的前 3 个字符。在我看来,第三个捕获组 _([a-z0-9]{1,3})_ 是在下划线 之间说 1-3 个字母数字字符,但我不知道如何“强制使用下划线定界符”,或者否则告诉它该组可能不在那里,它现在正在查看描述性文本。这可以在演示代码中看到,其中第一个和最后一个文件名不使用议程编号。

感谢任何帮助。

可选标识符 ? 用于最后一件事,字符或组。所以表达式 ([a-z0-9]{1,3})_? 使下划线成为可选的,但前面的组不是。解决方法是把下划线移到括号里。

^(\d{4}[_]?\d{2}[_]?\d{2})_(\w{2,3})_([a-z0-9]{1,3}_)?(.+)?.pdf

此外,[_]? 可以简化为 _?,文件名句点应该被转义(否则它们是通配符),我个人喜欢使用 [=17] 来命名我的组=] 语法。将所有这些放在一起你会得到:

^(?<date>\d{4}_?\d{2}_?\d{2})_(?<meeting_type>\w{2,3})_(?<agenda>[a-z0-9]{1,3}_)?(?<description>.+)?\.pdf$

此处演示:https://regex101.com/r/BUKCih/1

更新:

我根据评论做了一些更新。正如@Chris Maurer 所说,我在末尾添加了 $ 以强制“文件名结束”。这会阻止 file.pdf.txt 通过。我还制作了一个子组并将名称移到该组中,这允许尾随下划线不包含在命名组中。我将留下 Chris 关于单独收紧最后一个匹配组的其他评论,尽管我同意它,如果 OP 使用 [a-z0-9]+ 或类似文件,他们可能会发现几个不符合要求的文件。我不记得副手是否 PHP 支持 POSIX 但如果支持 [:alnum:] 也可以使用。

^(?<date>\d{4}_?\d{2}_?\d{2})_(?<meeting_type>\w{2,3})_((?<agenda>[a-z0-9]{1,3})_)?(?<description>.+)?\.pdf$

在此处更新演示:https://regex101.com/r/ebmxkF/1