使用正则表达式的自定义 realpath()
Custom realpath() using regex
我想创建我个人的 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"
它只删除第一次出现的 (folder5/../):
"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/../../../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;
}
preg_replace('~(?<![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)~', '', $url, -1, $count)
中的$count
参数保留替换的次数,替换一直进行到找不到匹配为止。
输出:
folders/folder2
../folder2
folders/folder1/folder2
您也可以使用非正则表达式方法:
<?php
$strings = ["folders/folder1/folder5/../../folder2", "folders/folder1/../../../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
)
我想创建我个人的 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"
它只删除第一次出现的 (folder5/../):
"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/../../../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;
}
preg_replace('~(?<![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)~', '', $url, -1, $count)
中的$count
参数保留替换的次数,替换一直进行到找不到匹配为止。
输出:
folders/folder2
../folder2
folders/folder1/folder2
您也可以使用非正则表达式方法:
<?php
$strings = ["folders/folder1/folder5/../../folder2", "folders/folder1/../../../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
)