问题描述
我想创建我个人的 realpath() 函数,它使用正则表达式并且不希望该文件存在。
到目前为止我做了什么
function my_realpath (string $path): string {
if ($path[0] != '/') {
$path = __DIR__.'/../../'.$path;
}
$path = preg_replace("~/\./~",'',$path);
$path = preg_replace("~\w+/\.\./~",$path); // removes ../ from path
return $path;
}
哪里不正确
问题是如果我有这个字符串:
"folders/folder1/folder5/../../folder2"
"folders/folder1/../folder2"
问题
如何删除(使用正则表达式)所有文件夹后跟相同数量的“../”?
示例
"folders/folder1/folder5/../../folder2" -> "folders/folder2"
"folders/folder1/../../../folder2" -> "../folder2"
"folders/folder1/folder5/../folder2" -> "folders/folder1/folder2"
我们可以告诉正则表达式:“~(\w+){n}/(../){n}~”,n 是贪婪的,但在两组中都相同吗?
解决方法
您可以使用基于递归的模式,例如
preg_replace('~(?<=/|^)(?!\.\.(?![^/]))[^/]+/(?R)?\.\.(?:/|$)~','',$url)
参见regex demo。 详情:
-
(?<=/|^)
- 紧靠左边,必须有/
或字符串开头(如果字符串作为单独的字符串提供,则等于更有效的(?<![^/])
) -
(?!\.\.(?![^/]))
- 紧靠右侧,不应有..
后跟/
或字符串结尾 -
[^/]+
- 除/
之外的一个或多个字符 -
/
-/
字符 -
(?R)?
- 递归整个模式,可选 -
\.\.(?:/|$)
-..
后跟/
字符或字符串结尾。
见PHP demo:
$strings = ["folders/folder1/folder5/../../folder2","folders/folder1/../../../folder2","folders/folder1/folder5/../folder2"];
foreach ($strings as $url) {
echo preg_replace('~(?<=/|^)(?!\.\.(?![^/]))[^/\n]+/(?R)?\.\.(?:/|$)~',$url) . PHP_EOL;
}
// => folders/folder2,../folder2,folders/folder1/folder2
或者,您可以使用
(?<![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)
参见regex demo。 详情:
-
(?<![^/])
- 紧靠左边,必须有字符串开头或/
字符 -
(?!\.\.(?![^/]))
- 紧靠右侧,不应有..
后跟/
或字符串结尾 -
[^/]+
- 除/
之外的一个或多个字符 -
/\.\.
-/..
子串后跟... -
(?:/|$)
-/
或字符串结尾。
见PHP demo:
$strings = ["folders/folder1/folder5/../../folder2","folders/folder1/folder5/../folder2"];
foreach ($strings as $url) {
$count = 0;
do {
$url = preg_replace('~(?<![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)~',$url,-1,$count);
} while ($count > 0);
echo "$url" . PHP_EOL;
}
$count
中的 preg_replace('~(?<![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)~',$count)
参数保持替换的次数,并且替换一直持续到找不到匹配项为止。
输出:
folders/folder2
../folder2
folders/folder1/folder2
,
您也可以使用非正则表达式方法:
<?php
$strings = ["folders/folder1/folder5/../../folder2","folders/folder1/folder5/../folder2"];
function make_path($string) {
$parts = explode("/",$string);
$new_folder = [];
for ($i=0; $i<count($parts); $i++) {
if (($parts[$i] == "..") and count($new_folder) >= 1) {
array_pop($new_folder);
} else {
$new_folder[] = $parts[$i];
}
}
return implode("/",$new_folder);
}
$new_folders = array_map('make_path',$strings);
print_r($new_folders);
?>
这产生了
Array
(
[0] => folders/folder2
[1] => ../folder2
[2] => folders/folder1/folder2
)