1

输入:

http://foo/bar/baz/../../qux/

期望的输出:

http://foo/qux/

这可以使用正则表达式来实现(除非有人可以提出更有效的替代方案)。

如果是前向查找,它会很简单:

/\.\.\/[^\/]+/

虽然我不熟悉如何向后查找第一个“/”(即不做/[a-z0-9-_]+\/\.\./)。

我想到的解决方案之一是使用strrev然后应用正则表达式向前查找(第一个示例),然后执行strrev. 虽然我确信有一种更有效的方法。

4

3 回答 3

0

这不是我见过的最清楚的问题,但如果我明白你在问什么,我认为你只需要像这样切换你所拥有的:

/[^\/]+/\.\./

...然后将其替换为/

这样做直到没有更换,你应该有你想要的

编辑

您的尝试似乎尝试匹配正斜杠/和两个点\.\.,后跟一个斜杠/(或者\/- 它们都应该匹配相同的东西),然后是一个或多个非斜杠字符[^/]+,以斜杠结尾/。翻转它,您想找到一个斜线,后跟一个或多个非斜线字符和一个终止斜线,然后是两个点和一个最后一个斜线。

您可能会误以为正则表达式引擎会在运行过程中解析和使用内容(因此您不希望使用后跟不正确点数的目录名称),但这不是它通常的工作方式 - 一个正则表达式引擎在替换或返回任何内容之前匹配整个表达式。因此,您可以有两个点后跟一个目录名,或者一个目录名后跟两个点 - 这对引擎没有影响。

如果您尝试使用斜杠封闭的 Perl 样式语法,那么您当然需要使用\/任何您尝试匹配的斜杠,例如中间的斜杠,但我也建议匹配和替换封闭的斜杠url 也是:我认为 PHP 会类似于

preg_replace('/\/[^\/]+\/\.\.\//', '/', $input)

(??)

于 2013-10-04T14:00:47.663 回答
0

从技术上讲,您想要的是将 '/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

于 2013-10-04T14:58:57.747 回答
0

您应该能够使用此代码:

$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/
于 2013-10-04T15:06:35.810 回答