用于匹配UNC路径的PHP Regex

时间:2012-02-28 15:48:10

标签: php regex

我正在使用一些正则表达式在PHP中用于验证通过表单传递的UNC路径。它的格式应为:

\\server\something

...并允许进一步的子文件夹。为了保持一致性而剥离尾部斜杠可能是件好事,尽管如果需要的话我可以用substr轻松地做到这一点。

我在线阅读在PHP中匹配单个反斜杠需要4个反斜杠(当使用“C like string”时)并且我想我明白为什么(PHP转义(例如2 = 1,所以4 = 2),然后正则表达式引擎转义(剩下的2 = 1)。我已经看到以下两个引用为等效的合适的正则表达式来匹配单个反斜杠:

$regex = "/\\\\/s";

或显然这也是:

$regex = "/[\\]/s";

然而,这些产生了不同的结果,这与我最终目标相匹配,以匹配完整的UNC路径。

要查看我是否可以匹配两个反斜杠,我使用以下内容进行测试:

$path = "\\\\server";
echo "the path is: $path <br />"; // which is \\server
$regex = "/\\\\\\\\\/s";
if (preg_match($regex, $path)) 
{
    echo "matched";
}
else
{
    echo "not matched";
}

上面似乎匹配两个或更多反斜杠:(模式为8斜杠,转换为2,那么为什么3个反斜杠($path = "\\\\\\server")的输入匹配?

我想也许以下方法可行:

$regex = "/[\\][\\]/s";

再次,不:(

在我跳出窗户之前请帮助大声笑:)

2 个答案:

答案 0 :(得分:6)

使用这个小宝石:

$UNC_regex = '=^\\\\\\\\[a-zA-Z0-9-]+(\\\\[a-zA-Z0-9`~!@#$%^&(){}\'._-]+([ ]+[a-zA-Z0-9`~!@#$%^&(){}\'._-]+)*)+$=s';

来源:http://regexlib.com/REDetails.aspx?regexp_id=2285(采用PHP字符串转义)

上面显示的RegEx匹配有效主机名(只允许几个有效字符)和主机名后面的路径部分(允许多个但不是所有字符)


关于反斜杠问题的旁注:

  • 当您使用double quotes (") to enclose your string时,您必须了解PHP特殊字符转义。"\\"是PHP中的单个\

  • 重要提示:即使使用单引号('),也必须转义这些反斜杠。
    除了少数例外情况,PHP string with single quotes将字符串中的所有字符串(非转义)取出:
    1. 反斜杠后跟反斜杠(\\)被解释为单个反斜杠。
      'C:\\*.*' =&gt; C:\*.*
    2. 反斜杠后跟单引号(\')被解释为单引号。
      'I\'ll be back' =&gt; I'll be back
    3. 反斜杠后跟其他任何内容都被解释为反斜杠 ('Just a \ somewhere' =&gt; Just a \ somewhere

  • 此外,您必须了解PCRE escape sequences
    RegEx解析器将\视为字符类,因此您需要再次为RegEx转义它。
    要匹配两个\\,您必须写$regex = "\\\\\\\\"$regex = '\\\\\\\\'

    来自PHP docs on PCRE escape sequences

      

    单引号和双引号PHP字符串具有反斜杠的特殊含义。因此,如果\必须与正则表达式\匹配,则必须在PHP代码中使用“\\”或“\\”。

  •   

     

关于你的问题:

  

为什么输入3个反斜杠($ path =“\\\ server”)与正则表达式"/\\\\\\\\/s"匹配?

原因是您没有定义边界(使用^作为开头,$作为字符串结尾),因此它找到\\ “某处”导致积极的匹配。要获得预期的结果,您应该执行以下操作:

$regex = '/^\\\\\\\\[^\\\\]/s';

以上RegEx有两项修改:

  • ^在开头只匹配字符串开头的两个\\
  • [^\\]否定字符类说:没有后跟一个额外的反斜杠

关于你上一次的RegEx:

$regex = "/[\\][\\]/s";

你有一个混乱(见上文澄清),反斜杠在这里逃避。 PHP将"/[\\][\\]/s"解释为/[\][\]/s,这将使RegEx失败,因为\是RegEx中的保留字符,因此必须进行转义。

您的RegEx的这个变体可以使用,但匹配任何两个反斜杠的出现的原因与上面已经解释的相同:

$regex = '/[\\\\][\\\\]/s';

答案 1 :(得分:3)

也回显你的正则表达式,所以你看到实际模式是什么,在PHP中编写这些斜杠对于模式来说可能变得很笨拙,所以你可以验证它是正确的。

此外,您应该将^放在模式的开头,以便从字符串start和$匹配到结尾,以指定必须匹配整个字符串。

\\server\something

正则表达式:

 ~^\\\\server\\something$~

PHP字符串:

$pattern = '~^\\\\\\\\server\\\\something$~';

对于重复,您想要说服务器存在,然后是一个或多个\something部分。如果服务器就像某样东西,可以简化:

^\\(?:\\[a-z]+){2,}$

PHP字符串:

$pattern = '~^\\\\(?:\\\\[a-z]+){2,}$~';

由于在单引号字符串中应该如何编写\字符存在一些混淆:

# Output:
#
# * Definition as '\\' ....... results in string(1) "\"
# * Definition as '\\\\' ..... results in string(2) "\\"
# * Definition as '\\\\\\' ... results in string(3) "\\\"

$slashes = array(
    '\\',
    '\\\\',
    '\\\\\\',
);

foreach($slashes as $i => $slashed) {
    $definition = sprintf('%s ', var_export($slashed, 1));
    ob_start();
    var_dump($slashed);
    $result = rtrim(ob_get_clean());    
    printf(" * Definition as %'.-12s results in %s\n", $definition, $result);
}