【问题标题】:Custom realpath() using regex使用正则表达式自定义 realpath()
【发布时间】:2021-06-14 11:11:04
【问题描述】:

我想创建我的个人 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"

它只删除第一次出现的(文件夹 5/../):

"folders/folder1/../folder2"

问题

如何删除(使用正则表达式)后跟相同数量“../”的所有文件夹?

示例

"folders/folder1/folder5/../../folder2" -> "folders/folder2"

"folders/folder1/../../../folder2" -> "../folder2"

"folders/folder1/folder5/../folder2" -> "folders/folder1/folder2"

我们可以告诉正则表达式:“~(\w+){n}/(../){n}~”,n 是贪婪的,但在两组中都相同?

【问题讨论】:

    标签: php regex regex-group realpath


    【解决方案1】:

    您可以使用基于递归的模式,例如

    preg_replace('~(?<=/|^)(?!\.\.(?![^/]))[^/]+/(?R)?\.\.(?:/|$)~', '', $url)
    

    请参阅regex demo详情

    • (?&lt;=/|^) - 紧靠左边,必须有 / 或字符串开头(如果字符串作为单独的字符串提供,则等于更高效的 (?&lt;![^/])
    • (?!\.\.(?![^/])) - 紧靠右边,不应有 .. 后跟 / 或字符串结尾
    • [^/]+ - 除了/ 之外的一个或多个字符
    • / - 一个 / 字符
    • (?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详情

    • (?&lt;![^/]) - 紧靠左边,必须有字符串开头或/ char
    • (?!\.\.(?![^/])) - 紧靠右侧,不应有 .. 后跟 / 或字符串结尾
    • [^/]+ - 除了/ 之外的一个或多个字符
    • /\.\. - /.. 子字符串后跟...
    • (?:/|$) - / 或字符串结尾。

    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('~(?&lt;![^/])(?!\.\.(?![^/]))[^/]+/\.\.(?:/|$)~', '', $url, -1, $count) 中的 $count 参数保存替换的次数,并且替换一直进行到找不到匹配项为止。

    输出:

    folders/folder2
    ../folder2
    folders/folder1/folder2
    

    【讨论】:

      【解决方案2】:

      您也可以使用非正则表达式方法:

      <?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
      )
      

      a demo on ideone.com

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-29
        • 2015-03-11
        • 1970-01-01
        • 2013-03-24
        • 2016-07-22
        • 2015-02-27
        • 2018-06-17
        • 1970-01-01
        相关资源
        最近更新 更多