php - Preg_match 正在“忽略”捕获组分隔符
问题描述
我们的数据库中存储了数千个结构化文件名,不幸的是,数百个已手动更改为不符合我们命名约定的名称。使用正则表达式,我试图匹配正确的文件名以识别所有错误命名的文件名。这些文件都与会议议程相关,并在名称中使用日期、会议类型、议程项目# 和描述。
我们的命名约定是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
我用来匹配这些文件的正则表达式如下(正则表达式演示):
/^(\d{4}[_]?\d{2}[_]?\d{2})_(\w{2,3})_([a-z0-9]{1,3})_?(.+)?.pdf/i
问题:
一般来说,它工作正常,但如果议程编号(“bbb”)不在文件名中,正则表达式会捕获并返回描述的前 3 个字符。在我看来,第 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
此外,[_]?
可以简化为_?
,文件名句点应该被转义(否则它们是通配符),我个人喜欢使用(?<name>)
语法命名我的组。把所有这些放在一起,你会得到:
^(?<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 关于单独收紧最后一个匹配组的其他评论,如果他们使用[a-z0-9]+
或类似的,OP 可能会发现一些不合格的文件。我不记得 PHP 是否支持 POSIX,但如果支持[:alnum:]
也可以使用。
^(?<date>\d{4}_?\d{2}_?\d{2})_(?<meeting_type>\w{2,3})_((?<agenda>[a-z0-9]{1,3})_)?(?<description>.+)?\.pdf$
推荐阅读
- bash - 使用 CLI 等待操作完成
- python - 如何从文件中删除多余的 \n?
- gunicorn - pybottle gunicorn gevent 不共享全局字典
- mongodb - 用于搜索字符串是否包含在字段中的 Mongoose 文本索引
- java - 我的 Do-While 循环不检查我的状况?
- python - 使用 pyspark 复制组内的值
- apache - 如何将所有流量重定向到除主页之外的新域
- docker - Docker:使用组权限安装卷?
- javascript - tsconfig.json 中的 **/node_modules/* 是什么意思?
- java - 如何过滤复杂对象的列表,以便如果两个具有字段值,我会根据条件删除一个