4

示例 1:domain.com/dir_1/dir_2/dir_3/./../../../
应该在浏览器中自然解析为 =domain.com/

示例 2:domain.com/dir_1/dir_2/dir_3/./../../../test/././../new_dir/
应该解析为domain.com/new_dir/

示例 3:domain.com/dir_1/dir_2/dir_3/./../../../test/dir4/../final
应该解析为domain.com/test/final

我怎样才能遍历字符串来做到这一点?我觉得此时for()循环会感到困惑。

Transform relative path into absolute URL using PHP and PHP: How to resolve a relative url don't work for me in this case 中提供的答案。我不应该需要一个参考点(基础),因为目标是清理我已经拥有的东西。

这不是PHP 的副本 - 无法打开流:没有这样的文件或目录

4

2 回答 2

9

这是一个比您正在考虑的更简单的问题。您需要做的就是explode()/角色上,并使用堆栈解析出所有单独的片段。当你从左到右遍历数组时,如果你看到.,什么也不做。如果看到..,从堆栈中弹出一个元素。否则,将一个元素压入堆栈。

$str = 'domain.com/dir_1/dir_2/dir_3/./../../../';
$array = explode( '/', $str);
$domain = array_shift( $array);

$parents = array();
foreach( $array as $dir) {
    switch( $dir) {
        case '.':
        // Don't need to do anything here
        break;
        case '..':
            array_pop( $parents);
        break;
        default:
            $parents[] = $dir;
        break;
    }
}

echo $domain . '/' . implode( '/', $parents);

这将正确解析所有测试用例中的 URL。

请注意,错误检查留给用户作为练习(即,当$parents堆栈为空并且您尝试从中弹出一些东西时)。

于 2013-02-14T20:50:25.513 回答
1

你想要的是一个“replaceDots”功能。

它的工作原理是记住最后一个有效项目的位置,然后如果你得到点然后删除该项目。完整的描述在这里“删除点段” https://www.rfc-editor.org/rfc/rfc3986。在 RFC 页面上搜索 Remove Dot Segments。

你需要不止一个循环。内部循环向前扫描并查看下一部分,然后如果它是点,则跳过当前部分等,但它可能比这更棘手。或者考虑将其分解为多个部分,然后遵循算法。

  1. 当输入缓冲区不为空时,循环如下:

    A. 如果输入缓冲区以“../”或“./”前缀开头,则从输入缓冲区中删除该前缀;否则,

    B. 如果输入缓冲区以前缀“/./”或“/.”开头,其中“.” 是一个完整的路径段,然后在输入缓冲区中将该前缀替换为“/”;否则,

    C. 如果输入缓冲区以前缀“/../”或“/..”开头,其中“..”是完整的路径段,则在输入缓冲区中将该前缀替换为“/”并删除来自输出缓冲区的最后一段及其前面的“/”(如果有);否则,

    D. 如果输入缓冲区只包含“.” 或“..”,然后将其从输入缓冲区中删除;否则,

    E. 将输入缓冲区中的第一个路径段移动到输出缓冲区的末尾,包括初始“/”字符(如果有)和任何后续字符,直到但不包括下一个“/”字符或末尾的输入缓冲区。

  2. 最后,输出缓冲区作为 remove_dot_segments 的结果返回。功能。

它的工作原理是记住最后一个有效项目的位置,然后如果你得到点然后删除该项目。完整的描述在这里

这是我在 C++ 中的版本...

ortl_funcimp(len_t) _str_remove_dots(char_t* s, len_t len) {
  len_t x,yy;
  /*
    Modifies the string in place by copying parts back. Not
    sure if this is the best way to do it since it involves
    many copies for deep relatives like ../../../../../myFile.cpp

    For each ../ it does one copy back. If the loop was implemented
    using writing into a buffer, you would have to do both, so this
    seems to be the best technique.
  */
  __checklenx(s,len);
  x = 0;
  while (x < len) {
    if (s[x] == _c('.')) {
      x++;
      if (x < len) {
        if (s[x] == _c('.')) {
          x++;
          if (x < len) {
            if (s[x] == _c('/')) { // ../
              mem_move(&s[x],&s[x-2],(len-x)*sizeof(char_t));
              len -= 2;
              x -= 2;
            }
            else x++;
          }
          else len -= 2;// .. only
        }
        else if (s[x] == _c('/')){ // ./
          mem_move(&s[x],&s[x-1],(len-x)*sizeof(char_t));
          len--;
          x--;
        }
      }
      else --len;// terminating '.', remove
    }
    else if (s[x] == _c('/')) {
      x++;
      if (x < len) {
        if (s[x] == _c('.')) {
          x++;
          if (x < len) {
            if (s[x] == _c('/')) { // /./
              mem_move(&s[x],&s[x-2],(len-x)*sizeof(char_t));
              len -= 2;
              x -= 2;
            }
            else if (s[x] == _c('.')) { // /..
              x++;
              if (x < len) { //
                if (s[x] == _c('/')) {// /../
                  yy = x;
                  x -= 3;
                  if (x > 0) x--;
                  while ((x > 0) && (s[x] != _c('/'))) x--;
                  mem_move(&s[yy],&s[x],(len-yy) * sizeof(char_t));
                  len -= (yy - x);
                }
                else {
                  x++;
                }
              }
              else {// ends with /..
                x -= 3;
                if (x > 0) x--;
                while (x > 0 && s[x] != _c('/')) x--;
                s[x] = _c('/');
                x++;
                len = x;
              }
            }
            else x++;
          }
          else len--;// ends with /.
        }
        else x++;
      }
    }
    else x++;
  }
  return len;
}
于 2013-02-14T20:38:36.610 回答