PHP 和正则表达式 - 在标题中查找特定字符串(字符串)



我被存储在数组中的月份在意大利,像这样:

$array = [
"gennaio" => "1",
"febbraio" => "2",
"marzo" => "3",
"aprile" => "4",
"maggio" => "5",
"giugno" => "6",
"luglio" => "7",
"agosto" => "8",
"settembre" => "9",
"ottobre" => "10",
"novembre" => "11",
"dicembre" => "12"
];

我也得到了这个标题:

$title1 = "Nota_382_del_16 marzo_2016.pdf";
$title2 = "OCDPC 382 del 16_agosto_2016.pdf";
$title3 = "OCDPC_382_del 16 _agosto 2016.pdf";
$title4 = "OCDPC_382_dal 16agosto 2016.pdf";
$title5 = "OCDPC_382 dall 16luglio2016.pdf";
$title6 = "OCDPC_382 da 16agosto_2016.pdf";
$title7 = "OCDPC_382_del_16_settembre 2016.pdf";
$title8 = "OCDPC_382 di 16 _agosto.2016.pdf";
$title9 = "OCDPC_382_del-16-agosto 2016.pdf";
$title10 = "Dipartimento OCDPC 382_del-16-agosto-2016.pdf";
$title11 = "OCDPC_382 dall'16-febbraio-2016.pdf";
$title12 = "OCDPC_382 dal'16-agosto-2016 - Dipartimentocivile.pdf";

在每个标题中,我想获得完整的日期,如16 settembre 2016,然后将其格式化为16/09/2016

我在格式化日期方面没有问题,但我的主要问题是使用正确的regex来捕获它,然后将月份名称更改为数字。对于更改月份上的数字,我可以用switch语句来管理它。

任何类型的帮助将不胜感激!

编辑:到现在为止,我是这样管理的:

(?<![^W_])?del?s*Kd+.?d+.?20[0-2][0-9]

当月份是由数字而不是名称引用时,实际的正则表达式捕获日期。

但这是一个非常具体的案例,我不是regex专家…

Regex

虽然@WiktorStribiżew已经回答了这个问题,但我建议对正则表达式采取稍微不同的看法…

/(dd?)[._ -]*([a-z]+)[._ -]*(d{4})/i
/                                           : Pattern delimiter
(dd?)                                    : Matches the day (1 or 2 numbers) and assigns to a capture group
[._ -]*                             : Mathces a delimiter 0 or more times
([a-z]+)                     : Matches the textual month and assigns to a capture group
[._ -]*              : Mathces a delimiter 0 or more times
(d{4})       : Matches the year (4 numbers) and assigns to a capture group
/      : Pattern delimiter
i     : Makes the regex case insensitive, just in case

…这样更容易阅读和理解。当涉及到日期分隔符(或缺少日期分隔符)时,它也稍微更具体一些,因此您不太可能发生冲突。

代码范例
$months = [
"gennaio" => "1",
"febbraio" => "2",
"marzo" => "3",
"aprile" => "4",
"maggio" => "5",
"giugno" => "6",
"luglio" => "7",
"agosto" => "8",
"settembre" => "9",
"ottobre" => "10",
"novembre" => "11",
"dicembre" => "12",
];


$titles = [
"Nota_382_del_16 marzo_2016.pdf",
"OCDPC 382 del 16_agosto_2016.pdf",
"OCDPC_382_del 16 _agosto 2016.pdf",
"OCDPC_382_dal 16agosto 2016.pdf",
"OCDPC_382 dall 16luglio2016.pdf",
"OCDPC_382 da 16agosto_2016.pdf",
"OCDPC_382_del_16_settembre 2016.pdf",
"OCDPC_382 di 16 _agosto.2016.pdf",
"OCDPC_382_del-16-agosto 2016.pdf",
"Dipartimento OCDPC 382_del-16-agosto-2016.pdf",
"OCDPC_382 dall'16-febbraio-2016.pdf",
"OCDPC_382 dal'16-agosto-2016 - Dipartimentocivile.pdf",
];
foreach ($titles as $title) {
preg_match('/(dd?)[._ -]*([a-z]+)[._ -]*(d{4})/i', $title, $dateParts);
echo $dateParts[1], "/", $months[strtolower($dateParts[2])], "/", $dateParts[3], " ", PHP_EOL ;
}

/* Potentially easier to read version:
foreach($titles as $title){
preg_match('/(dd?)[._ -]*([a-z]+)[._ -]*(d{4})/i', $title, $dateParts);
list(, $day, $month, $year) = $dateParts;
$month = $months[strtolower($month)];
echo "$day/$month/$year", PHP_EOL;
}
*/

输出:

16/3/2016
16/8/2016
16/8/2016
16/8/2016
16/7/2016
16/8/2016
16/9/2016
16/8/2016
16/8/2016
16/8/2016
16/2/2016
16/8/2016

可以使用

(?<!d)d{1,2}[W_]*p{L}+[W_]*d{4}(?!d)
(?<!d)(d{1,2})[W_]*(p{L}+)[W_]*(d{4})(?!d)                          // With numbered groups
(?<!d)(?P<day>d{1,2})[W_]*(?P<month>p{L}+)[W_]*(?P<year>d{4})(?!d)  // With named groups

参见regex演示。细节:

  • (?<!d)-当前位置的左边不允许有数字
  • d{1,2}-一个或两个数字
  • [W_]*-零个或多个非字母数字字符
  • p{L}+-一个或多个Unicode字母
  • [W_]*- 0个或多个非字母数字字符
  • d{4}—四位数字(如果年份可以是两位数字,可以使用d{2}(?:d{2})?)
  • (?!d)-当前位置的右边不允许有数字。

在PHP中,你可以像这样使用

if (preg_match('~(?<!d)(?P<day>d{1,2})[W_]*(?P<month>p{L}+)[W_]*(?P<year>d{4})(?!d)~u', $string, $match)) {
echo $match["day"] . PHP_EOL;
echo $match["month"] . PHP_EOL;
echo $match["year"];
}

查看PHP演示

最新更新