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()この時点でループが混乱するような気がします。

PHPとPHPを使用して相対パスを絶対URLに変換するで提供された回答:この場合、相対URLを解決する方法は機能しません。私がすでに持っているものをクリーンアップする目的があるので、参照ポイント(ベース)は必要ありません。

これは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ページでドットセグメントの削除を検索します。

複数のループが必要です。内側のループは前方をスキャンして次の部分を調べ、ドットの場合は現在の部分がスキップされるなどですが、それよりも難しい場合があります。または、それをいくつかの部分に分割してから、アルゴリズムに従うことを検討してください。

  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 に答える