如何preg_matchcontent-disposition中的所有三种情况header?
How to preg_match all three cases in the content-disposition header?
我正在尝试解码 content-disposition header(来自 curl)以使用以下正则表达式获取文件名:
<?php
$str = 'attachment;filename="unnamed.jpg";filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])([^"\']+)/m', $str, $matches);
print_r($matches);
因此,如果文件名在单引号或双引号中它会匹配,但如果文件名周围没有引号(这可能会发生),它就会失败
$str = 'attachment;filename=unnamed.jpg;filename*=unnamed.jpg';
现在我正在使用两个正则表达式(if-else),但我只是想了解是否可以在一个正则表达式中执行?仅供自己学习掌握正则表达式。
一种方法是在单个正则表达式中使用交替来匹配 single/double 带引号的文件名或完全不带引号的文件名。请注意,这种方法的一个副作用是我们在正则表达式中引入了更多的捕获组。所以我们需要一些额外的逻辑来处理这个。
<?php
$str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
$result = preg_match('/^.*?filename=(?:(?:(["\'])([^"\']+))|([^"\';]+))/m',
$str, $matches);
print_r($matches);
$index = count($matches) == 3 ? 2 : 3;
if ($result) {
echo $matches[$index];
}
else {
echo "filename not found";
}
?>
您可以将捕获组设置为可选 (["\'])?
和 ?
,例如:
并在非捕获组中的正则表达式末尾添加一个分号或字符串结尾,该组检查是否存在 ;
或行尾 (?:;|$)
^.*?filename=(["\'])?([^"\']+)?(?:;|$)
$str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])?([^"\']+)?(?:;|$)/m', $str, $matches);
print_r($matches);
也可以使用\K
重新设置上报匹配的起始点,然后匹配直到遇到双引号或分号[^";]+
。这只会 return 文件名。
foreach ($strings as $string) {
preg_match('/^.*?filename="?\K[^";]+/m', $string, $matches);
print_r($matches);
}
我将使用 branch reset 功能 (?|...|...|...)
提供更易读的模式并避免为引号创建捕获组。在分支重置组中,每个捕获组的每个备选方案都具有相同的编号:
if ( preg_match('~filename=(?|"([^"]*)"|\'([^\']*)\'|([^;]*))~', $str, $match) )
echo $match[1], PHP_EOL;
无论哪种选择成功,捕获总是在组 1 中。
只是把我的两分钱放进去 - 你可以使用 条件正则表达式:
filename=(['"])?(?(1)(.+?)|([^;]+))
分解后,这表示:
filename= # match filename=
(['"])? # capture " or ' into group 1, optional
(?(1) # if group 1 was set ...
(.+?) # ... then match up to
| # else
([^;]+) # not a semicolon
)
之后,您需要检查第 2 组或第 3 组是否存在。
或者,使用(经常被忽视的)分支重置来寻找@Casimir 的答案。
我正在尝试解码 content-disposition header(来自 curl)以使用以下正则表达式获取文件名:
<?php
$str = 'attachment;filename="unnamed.jpg";filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])([^"\']+)/m', $str, $matches);
print_r($matches);
因此,如果文件名在单引号或双引号中它会匹配,但如果文件名周围没有引号(这可能会发生),它就会失败
$str = 'attachment;filename=unnamed.jpg;filename*=unnamed.jpg';
现在我正在使用两个正则表达式(if-else),但我只是想了解是否可以在一个正则表达式中执行?仅供自己学习掌握正则表达式。
一种方法是在单个正则表达式中使用交替来匹配 single/double 带引号的文件名或完全不带引号的文件名。请注意,这种方法的一个副作用是我们在正则表达式中引入了更多的捕获组。所以我们需要一些额外的逻辑来处理这个。
<?php
$str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
$result = preg_match('/^.*?filename=(?:(?:(["\'])([^"\']+))|([^"\';]+))/m',
$str, $matches);
print_r($matches);
$index = count($matches) == 3 ? 2 : 3;
if ($result) {
echo $matches[$index];
}
else {
echo "filename not found";
}
?>
您可以将捕获组设置为可选 (["\'])?
和 ?
,例如:
并在非捕获组中的正则表达式末尾添加一个分号或字符串结尾,该组检查是否存在 ;
或行尾 (?:;|$)
^.*?filename=(["\'])?([^"\']+)?(?:;|$)
$str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])?([^"\']+)?(?:;|$)/m', $str, $matches);
print_r($matches);
也可以使用\K
重新设置上报匹配的起始点,然后匹配直到遇到双引号或分号[^";]+
。这只会 return 文件名。
foreach ($strings as $string) {
preg_match('/^.*?filename="?\K[^";]+/m', $string, $matches);
print_r($matches);
}
我将使用 branch reset 功能 (?|...|...|...)
提供更易读的模式并避免为引号创建捕获组。在分支重置组中,每个捕获组的每个备选方案都具有相同的编号:
if ( preg_match('~filename=(?|"([^"]*)"|\'([^\']*)\'|([^;]*))~', $str, $match) )
echo $match[1], PHP_EOL;
无论哪种选择成功,捕获总是在组 1 中。
只是把我的两分钱放进去 - 你可以使用 条件正则表达式:
filename=(['"])?(?(1)(.+?)|([^;]+))
分解后,这表示:
filename= # match filename=
(['"])? # capture " or ' into group 1, optional
(?(1) # if group 1 was set ...
(.+?) # ... then match up to
| # else
([^;]+) # not a semicolon
)
之后,您需要检查第 2 组或第 3 组是否存在。
或者,使用(经常被忽视的)分支重置来寻找@Casimir 的答案。