PHP正则表达式优化:大篇幅学生作文中特定格式日期匹配需求
搞定PHP正则匹配作文中的特定日期格式
没问题,针对你需要从学生作文里匹配特定格式日期的需求,我整理了一套精准的正则方案,覆盖你提到的所有格式,同时支持()和[]两种包裹方式,还能处理大小写问题。
正则表达式解析
先直接上最终的正则(带注释版方便你理解):
/(?:\[|\() # 匹配开头的[或(,非捕获分组避免冗余捕获 (?: (?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?) -\d{4} # 匹配「月份缩写/全称-年份」格式 | \d{4}- (?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?) # 匹配「年份-月份缩写/全称」格式 | \d{4} # 匹配纯四位年份格式 ) (?:\]|\))/ix # 匹配结尾的]或),x修饰符允许正则换行注释,i修饰符忽略大小写
如果不需要注释,直接用精简版:
/(?:\[|\()(?:(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)-\d{4}|\d{4}-(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(ember)?)|\d{4})(?:\]|\))/i
关键特性
- 大小写兼容:通过
i修饰符,不管是nov还是NOV、November都能匹配 - 双包裹支持:同时处理
()和[]包裹的日期 - 全格式覆盖:完美匹配你列出的5种日期格式:纯年份、月份缩写/全称-年份、年份-月份缩写/全称
- 非捕获分组优化:用
(?:...)减少不必要的捕获组,让匹配结果更整洁
PHP代码示例
因为是大篇幅作文,大概率需要匹配所有符合条件的日期,所以用preg_match_all更合适:
// 模拟学生提交的作文内容 $essayContent = "在1990年的秋天,作者提到了(1994)的重要事件,还有[nov-1994]的旅行经历,(november-1994)的会议记录,以及[1994-nov]的日记片段,最后提到(1994-november)的毕业仪式。无关内容比如(abc123)不会被匹配。"; // 使用精简版正则 $datePattern = '/(?:\[|\()(?:(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(ember)?)-\d{4}|\d{4}-(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(ember)?|dec(ember)?)|\d{4})(?:\]|\))/i'; // 匹配所有符合条件的日期 preg_match_all($datePattern, $essayContent, $matchedDates); // 输出匹配结果 echo "匹配到的日期:\n"; print_r($matchedDates[0]);
运行后会输出:
匹配到的日期: Array ( [0] => (1994) [1] => [nov-1994] [2] => (november-1994) [3] => [1994-nov] [4] => (1994-november) )
进阶需求:提取不带包裹符号的日期
如果你只需要里面的日期内容(比如去掉()或[]),只需调整正则,把内部日期部分用捕获分组:
/(?:\[|\()((?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(ember)?|dec(ember)?)-\d{4}|\d{4}-(?:jan(uary)?|feb(ruary)?|mar(ch)?|apr(il)?|may|jun(e)?|jul(y)?|aug(ust)?|sep(tember)?|oct(ober)?|nov(ember)?|dec(ember)?)|\d{4})(?:\]|\))/i
此时$matchedDates[1]就是不带包裹符号的日期数组:
Array ( [0] => 1994 [1] => nov-1994 [2] => november-1994 [3] => 1994-nov [4] => 1994-november )
内容的提问来源于stack exchange,提问作者user3393366
相关产品推荐
相关产品推荐

