输入:
http://foo/bar/baz/../../qux/
期望的输出:
http://foo/qux/
这可以使用正则表达式来实现(除非有人可以提出更有效的替代方案)。
如果是前向查找,它会很简单:
/\.\.\/[^\/]+/
虽然我不熟悉如何向后查找第一个“/”(即不做/[a-z0-9-_]+\/\.\./)。
我想到的解决方案之一是使用strrev然后应用正则表达式向前查找(第一个示例),然后执行strrev. 虽然我确信有一种更有效的方法。
这不是我见过的最清楚的问题,但如果我明白你在问什么,我认为你只需要像这样切换你所拥有的:
/[^\/]+/\.\./
...然后将其替换为/
这样做直到没有更换,你应该有你想要的
编辑
您的尝试似乎尝试匹配正斜杠/和两个点\.\.,后跟一个斜杠/(或者\/- 它们都应该匹配相同的东西),然后是一个或多个非斜杠字符[^/]+,以斜杠结尾/。翻转它,您想找到一个斜线,后跟一个或多个非斜线字符和一个终止斜线,然后是两个点和一个最后一个斜线。
您可能会误以为正则表达式引擎会在运行过程中解析和使用内容(因此您不希望使用后跟不正确点数的目录名称),但这不是它通常的工作方式 - 一个正则表达式引擎在替换或返回任何内容之前匹配整个表达式。因此,您可以有两个点后跟一个目录名,或者一个目录名后跟两个点 - 这对引擎没有影响。
如果您尝试使用斜杠封闭的 Perl 样式语法,那么您当然需要使用\/任何您尝试匹配的斜杠,例如中间的斜杠,但我也建议匹配和替换封闭的斜杠url 也是:我认为 PHP 会类似于
preg_replace('/\/[^\/]+\/\.\.\//', '/', $input)
(??)
从技术上讲,您想要的是将 '/path1/path2/../../' 的段替换为 '/' 所需要做的就是匹配 'pathx/'^n'../'^n 这绝对是不是正则表达式(Context Free Lenguaje)......但大多数正则表达式库都支持一些非正则 lenguajes,并且可以(付出很多努力)管理那些类型的 lenguajes。
解决它的一个简单方法是留在正则表达式中并循环几次,将 '/[^./]+/../' 替换为 ''
如果你还是一步一步做,就需要先行和分组,但是写起来会很困难,(我不太习惯,但我会尝试)
编辑:
我只在 1 个正则表达式中找到了解决方案......但应该使用 PCRE 正则表达式
([^/.]+/(?1)?\.\./)
我的解决方案基于以下链接: Match a^nb^nc^n (eg "aabbbccc") using regular expressions (PCRE)
(请注意,第一部分中的点是“禁止的”,如果您想要更复杂的情况,则不能使用 path.1/path.2/,因为您应该承认它们,但在第一部分中禁止 '../' 为有效
此子表达式用于接受路径名,如 'path1/'
[^/.]+/
这个子表达式用于承认双点。
\.\./
您可以在https://www.debuggex.com/中测试正则表达式 (记得将其设置为 PCRE 模式)
这是一个工作副本: https ://eval.in/52675
您应该能够使用此代码:
$url = 'http://foo/bar/baz/../../qux/';
$url_parts = parse_url( $url );
$path = $url_parts['path'];
while(strstr($path, '..'))
$path = preg_replace('~[^/]*/\.{2}/~', '', $path);
$url_parts['path'] = $path;
$canoicalUrl = http_build_url(null, $url_parts);
echo $canoicalUrl;
输出:
http://foo/qux/