Preg_match 是 "ignoring" 捕获组定界符
Preg_match is "ignoring" a capture group delimiter
我们的数据库中存储了数千个结构化文件名,不幸的是,有数百个文件名已被手动更改为不符合我们命名约定的名称。使用正则表达式,我试图匹配正确的文件名以识别所有命名错误的文件。
这些文件都与会议议程相关,并在名称中使用日期、会议类型、议程项目#和描述。
我们的命名约定是 yyyymmdd_aa[_bbb]_ccccc.pdf
其中:
- yyyymmdd 是一个日期(并且可以选择使用下划线,例如 yyyy_mm_dd)
- aa 是一个 2-3 个字符的会议类型代码
- bbb 是 可选 议程项目
- ccccc 是文件的自由格式可变长度描述(仅限字母数字)
示例文件名:
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
我们的数据库中存储了数千个结构化文件名,不幸的是,有数百个文件名已被手动更改为不符合我们命名约定的名称。使用正则表达式,我试图匹配正确的文件名以识别所有命名错误的文件。 这些文件都与会议议程相关,并在名称中使用日期、会议类型、议程项目#和描述。
我们的命名约定是 yyyymmdd_aa[_bbb]_ccccc.pdf
其中:
- yyyymmdd 是一个日期(并且可以选择使用下划线,例如 yyyy_mm_dd)
- aa 是一个 2-3 个字符的会议类型代码
- bbb 是 可选 议程项目
- ccccc 是文件的自由格式可变长度描述(仅限字母数字)
示例文件名:
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