【问题标题】:regex - negative lookahead to exclude strings正则表达式 - 排除字符串的负前瞻
【发布时间】:2011-06-14 22:27:17
【问题描述】:

我正在尝试在文本中查找(并替换为其他内容)所有部分

  1. 以“/”开头
  2. 以“/”结尾
  3. 在两个 / 之间可以有任何东西,除了字符串 '.'和“..”。

(为了您的信息,我正在搜索和替换目录和文件名,因此应该排除“.”和“..”。)

这是我想出的正则表达式:

/(?!\.|\.\.)([^/]+)/

第二部分

([^/]+)

匹配每个字符序列,'/' 除外。不需要字符限制,我只是解释输入。

第一部分

(?!\.|\.\.)

使用否定的前瞻断言来排除字符串 '.'和'..'。

但是,这似乎不适用于带有 mb_ereg_replace() 的 PHP。

有人可以帮帮我吗?我看不出我的正则表达式有什么问题。

谢谢。

【问题讨论】:

  • 你想用什么替换?您还知道文件名可以包含 . 吗?您的解决方案似乎将其排除在外
  • 是这样的:for (; ($r = mb_ereg_replace('/(?!\.|\.\.)([^/]+)/', 'BLA', $path )) !== $input; $input = $r) { } 例如,如果输入是 '.../..',则最后一个 '..' 不会被 BLA 替换。
  • 对我来说是正确的。 php有转义字符吗?
  • @yes123 - 你是什么意思?我不允许任何东西(甚至是'...'),除非它是'.'或“..”。
  • 啊,好吧!没关系。还有你想换什么?

标签: php regex expression


【解决方案1】:

POSIX 正则表达式可能不支持负前瞻。 (我可能错了)

无论如何,由于 PCRE 正则表达式通常比 POSIX 更快,我认为您可以使用相同功能的 PCRE 版本,因为 PCRE 支持 utf8 以及使用 u 标志。

将此代码视为替代:

preg_replace('~/(?!\.|\.\.)([^/]+)/~u', "", $str);

编辑:更好的是使用:

preg_replace('~/(?!\.)([^/]+)/~u', "", $str);

【讨论】:

  • 我以前从未使用过 PCRE 正则表达式。 '~' 是什么意思?为什么我需要添加它?
  • @SevyD:~ 只是一个分隔符的选择。通常使用/,但由于/在你的表情中很突出,所以anubhava选择了不同的。
  • @Tomalak Geret'kal:感谢您的解释。 @Sevy D. PCRS 正则表达式通常被认为比 POSIX 正则表达式更好更快。您可以通过在 Google 上搜索来阅读有关它们的大量信息。也看看:php.net/manual/en/reference.pcre.pattern.modifiers.php.
  • (?!\.|\.\.) 最好写成(?!\.\.?),或者直接写成(?!\.),因为结尾没有以任何方式锚定,也没有使用匹配。
  • @Qtax:我更喜欢(?!\.\.?),它紧凑且可读性更强。
【解决方案2】:

这有点冗长,但它确实有效:

#/((\.[^./][^/]*)|(\.\.[^/]+)|([^.][^/]*))/#
^  |------------| |---------| |---------|
|        |             |               |
|        |        text starting with   |
|        |        two dots, that isn't |
|        |             "." or ".."     |
|  text starting with                  |
|  a dot, that isn't                text not starting
|  "." or ".."                         with a dot
|
delimiter

不匹配:

  • hi
  • //
  • /./
  • /../

匹配:

  • /hi/
  • /.hi/
  • /..hi/
  • /.../

http://regexpal.com/ 上玩一下。

我不确定你是否想允许//。如果你这样做,请在最后一个 / 之前粘贴 *

【讨论】:

  • 即使我恨你,我也必须在这里为 ascii 艺术给 +1
【解决方案3】:

我不反对正则表达式,但我会这样做:

function simplify_path($path, $directory_separator = "/", $equivalent = true){
  $path = trim($path);
  // if it's absolute, it stays absolute:
  $prepend = (substr($path,0,1) == $directory_separator)?$directory_separator:"";
  $path_array = explode($directory_separator, $path);
  if($prepend) array_shift($path_array);
  $output = array();
  foreach($path_array as $val){
    if($val != '..' || ((empty($output) || $last == '..') && $equivalent)) {
      if($val != '' && $val != '.'){
        array_push($output, $val);
        $last = $val;
      }
    } elseif(!empty($output)) {
        array_pop($output);
    }
  }
  return $prepend.implode($directory_separator,$output);
}

测试:

echo(simplify_path("../../../one/no/no/../../two/no/../three"));
// =>  ../../../one/two/three
echo(simplify_path("/../../one/no/no/../../two/no/../three"));
// =>  /../../one/two/three
echo(simplify_path("/one/no/no/../../two/no/../three"));
// =>  /one/two/three
echo(simplify_path(".././../../one/././no/./no/../../two/no/../three"));
// =>  ../../../one/two/three
echo(simplify_path(".././..///../one/.///./no/./no/../../two/no/../three/"));
// =>  ../../../one/two/three

我认为返回一个等效的字符串会更好,所以我尊重字符串开头出现的..

如果你不想要它们,你可以用第三个参数 $equivalent = false 来调用它:

echo(simplify_path("../../../one/no/no/../../two/no/../three", "/", false));
// =>  one/two/three
echo(simplify_path("/../../one/no/no/../../two/no/../three", "/", false));
// =>  /one/two/three
echo(simplify_path("/one/no/no/../../two/no/../three", "/", false));
// =>  /one/two/three
echo(simplify_path(".././../../one/././no/./no/../../two/no/../three", "/", false));
// =>  one/two/three
echo(simplify_path(".././..///../one/.///./no/./no/../../two/no/../three/", "/", false));
// =>  one/two/three

【讨论】:

    【解决方案4】:

    /(?!(\.|\.\.)/)([^/]+)/ 这将允许 ... 作为有效名称。

    【讨论】:

    • 这是正确的方向,但仍然无法正常工作。我正在做的是:用 '/' 替换 '/w/..' 以缩短我的路径。鉴于你的表达,我做了这个: for (; ($r = self::mb_ereg_replace('(^|/)(?!(\.|\.\.)/)([^/]+)/\ .\.(/|$)', '\\1', $path)) !== $path; $path = $r) { } 但是没有替换输入 '/name/..' 例如.我现在看不出哪里出了问题。
    • 你能做一个简单的前瞻来确保你的正则表达式引擎支持它们吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2011-10-14
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多