【问题标题】:Regex windows path validator正则表达式 windows 路径验证器
【发布时间】:2018-07-24 09:00:17
【问题描述】:

我试图找到一个用于 Javascript 的 windows 文件路径验证,但似乎没有一个能满足我想要的要求,所以我决定自己构建它。

要求如下:

  • 路径不能为空
  • 可以以 x:\、x:\\、\、// 开头,后跟文件名(无文件 需要扩展)
  • 文件名不能包含以下特殊字符::"|?*
  • 文件名不能以点或空格结尾

这是我想出的正则表达式: /^([a-z]:((\|/|\\|//))|(\\|//))[^:"|?*]+/i

但是有一些问题:

  • 它还验证包含特殊字符的文件名 规则中提到的
  • 它不包括最后一条规则(不能以:. 或空格结尾)

var reg = new RegExp(/^([a-z]:((\\|\/|\\\\|\/\/))|(\\\\|\/\/))[^<>:"|?*]+/i);
var startList = [
  'C://test',
  'C://te?st.html',
  'C:/test',
  'C://test.html',
  'C://test/hello.html',
  'C:/test/hello.html',
  '//test',
  '/test',
  '//test.html',
  '//10.1.1.107',
  '//10.1.1.107/test.html',
  '//10.1.1.107/test/hello.html',
  '//10.1.1.107/test/hello',
  '//test/hello.txt',
  '/test/html',
  '/tes?t/html',
  '/test.html',
  'test.html',
  '//',
  '/',
  '\\\\',
  '\\',
  '/t!esrtr',
  'C:/hel**o'
];

startList.forEach(item => {
  document.write(reg.test(item) + '  >>>   ' + item);
  document.write("<br>");
});

【问题讨论】:

  • 您的正则表达式缺少$(行尾),因此如果某些第一个字符满足它,则匹配路径。 \. 是点,\s 是空格,记得将它们转义为 RegExp

标签: javascript regex validation


【解决方案1】:

不幸的是,正则表达式的 JavaScript 风格不支持后视, 但幸运的是它确实支持前瞻,这是关键因素 如何构造正则表达式。

让我们从一些观察开始:

  1. 在点、斜杠、反斜杠或空格之后不能再出现另一个 点、斜杠或反斜杠。 “禁止”字符集还包括 \n,因为这些字符都不能是文件名的最后一个字符 或其片段(在点或(反)斜线之间)。

  2. 路径中允许的其他字符是您提到的字符 (除了...),但“排除列表”还必须包含一个点, 斜杠、反斜杠、空格和\n(第 1 点中提到的字符)。

  3. 在“初始部分”(C:\) 之后可以有多个实例 第 1 点或第 2 点中提到的字符。

考虑到这些点,我从 3 个部分构建了正则表达式:

  • “开始”部分,匹配驱动器号、冒号和最多 2 个 斜线(向前或向后)。
  • 第一种选择 - 点、斜杠、反斜杠或空格, 带有负前瞻 - 每个字符之后的“禁止”字符列表 上述字符(见第 1 点)。
  • 第二种选择 - 第 2 点中提到的字符。
  • 上述两种选择都可以多次出现(+ 量词)。

所以正则表达式如下:

  • ^ - 字符串的开头。
  • (?:[a-z]:)? - 驱动器号和冒号,可选。
  • [\/\\]{0,2} - 反斜杠或斜杠,0 到 2 次。
  • (?: - 非捕获组的开始,由于 + 而需要 后面的量词。
    • [.\/\\ ] - 第一种选择。
    • (?![.\/\\\n]) - 负前瞻 - “禁止”字符。
  • | - 或者。
    • [^&lt;&gt;:"|?*.\/\\ \n] - 第二种选择。
  • )+ - 非捕获组的结束,可能出现多次。
  • $ - 字符串结束。

如果您尝试单独匹配每个路径,请仅使用 i 选项。

但是如果你在不同的行中有多个路径,并匹配它们 一次性全局添加gm 选项。

有关工作示例,请参阅https://regex101.com/r/4JY31I/1

注意:我想!也应该被视为禁止 特点。如果您同意,请将其添加到第二个选项中,例如在*之后。

【讨论】:

  • 此示例错误地匹配“\\\foo”和“///foo”。根据给定的要求,“\\foo”也匹配不正确,尽管在这种情况下我会推迟要求,因为它是 SMB 服务器的有效匹配。除非“x:\\foo\\bar”等,否则我也会将“x:\\”作为有效案例推回。也被认为是有效的。路径字符串开头以外的任何地方的双斜杠都属于“错误但 Windows(有时)会原谅你的错误”类。
  • 您的第一个前提不正确(在 Windows 上),例如,C:..\..\folder\file.exe 是完全有效的 Windows 文件/路径声明。
  • 它还允许使用“+”和“=”符号。路径末尾的空格和/或句点,如果前面没有“\”或“/”,也不会被捕获...
【解决方案2】:

这可能对你有用:^(?!.*[\\\/]\s+)(?!(?:.*\s|.*\.|\W+)$)(?:[a-zA-Z]:)?(?:(?:[^&lt;&gt;:"\|\?\*\n])+(?:\/\/|\/|\\\\|\\)?)+$

你有一个演示 here

解释:

^
    (?!.*[\\\/]\s+)         # Disallow files beginning with spaces
    (?!(?:.*\s|.*\.|\W+)$)  # Disallow bars and finish with dot/space
    
    (?:[a-zA-Z]:)? # Drive letter (optional)
    
    (?:
          (?:[^<>:"\|\?\*\n])+  # Word (non-allowed characters repeated one or more)
          (?:\/\/|\/|\\\\|\\)?  # Bars (// or / or \\ or \); Optional
     )+ # Repeated one or more
     
$

【讨论】:

  • 您的正则表达式允许尾随空格或点前空格,但要求是不允许。
  • 至少,这允许在文件名中使用“+”字符,也不会在重复的句号或斜杠处回避......
  • 嗨@NetXpert。 + 是文件名的有效字符,并且 OP 没有声明他不希望该字符出现。此外,重复的柱是有效的。例如,尝试在 explorer C:\\\\\\\Windows 中写入。它应该可以工作。
  • @Julio -- FWIW,“+”是 DOS 中的文件连接符运算符,因此它在基本(短)文件名中是无效字符,原因与“”和“|”是。 (请参阅此处docs.microsoft.com/en-us/windows/win32/msi/filename 的“此外,短文件名不得包含以下字符”部分)。 IMO,如果您使重定向运算符无效,您也应该拒绝连接器。 ...而且,是的,它们基本上补偿了人们添加多余的反斜杠,但这并不能使它们实际上“正确”。
  • @Valdi_Bo 哪里规定不允许使用尾随空格或点前的空格?
【解决方案3】:

由于这篇文章似乎是搜索 RegEx Windows 路径验证模式的最佳结果之一,并且鉴于上述建议解决方案的注意事项/弱点,我'将包括我用于验证 Windows 路径的解决方案(我相信,它解决了之前在该用例中提出的所有问题)。

我无法想出一个可行的正则表达式,不管有没有前瞻和后视都可以完成这项工作,但我可以用两个来完成,没有任何前瞻或后瞻!

但请注意,连续的相对路径(即“..\..\folder\file.exe”)不会通过此模式(尽管在 处使用“..\”或“.\”字符串的开头)。斜杠前后或行尾的句点和空格,以及根据 Microsoft 的短文件名规范不允许的任何字符: https://docs.microsoft.com/en-us/windows/win32/msi/filename

第一个模式:

^   (?# <- Start at the beginning of the line #)
    (?# validate the opening drive or path delimiter, if present -> #)
        (?: (?# "C:", "C:\", "C:..\", "C:.\" -> #)
                (?:[A-Z]:(?:\.{1,2}[\/\\]|[\/\\])?)
            | (?# or "\", "..\", ".\", "\\" -> #)
                (?:[\/\\]{1,2}|\.{1,2}[\/\\])
        )?
    (?# validate the form and content of the body -> #)
        (?:[^\x00-\x1A|*?\v\r\n\f+\/,;"'`\\:<>=[\]]+[\/\\]?)+
$   (?# <- End at the end of the line. #)

这通常会验证路径结构和字符有效性,但它也允许出现问题,例如双句点、双反斜杠,以及在空格或句点之前和/或后跟空格或句点的句点和反斜杠。也允许以空格和/或句点结尾的路径。 为了解决这些问题,我使用另一种(类似)模式进行了第二次测试:

^   (?# <- Start at the beginning of the line #)
    (?# validate the opening drive or path delimiter, if present -> #)
        (?: (?# "C:", "C:\", "C:..\", "C:.\" -> #)
                (?:[A-Z]:(?:\.{1,2}[\/\\]|[\/\\])?)
            | (?# or "\", "..\", ".\", "\\" -> #)
                (?:[\/\\]{1,2}|\.{1,2}[\/\\])
        )?
    (?# ensure that undesired patterns aren't present in the string -> #)
        (?:([^\/\\. ]|[^\/. \\][\/. \\][^\/. \\]|[\/\\]$)*
    [^\x00-\x1A|*?\s+,;"'`:<.>=[\]]) (?# <- Ensure that the last character is valid #)
$   (?# <- End at the end of the line. #)

这验证了,在路径正文中,没有多个句点、多个斜杠、句号斜杠、空格斜杠、斜杠空格或斜杠句点出现,并且路径不以无效字符结尾.烦人的是,我必须重新验证 &lt;root&gt; 组,因为它是允许其中一些组合(即“.\”、“\\”和“..\”)的一个地方,我不想要那些使模式无效的。

这是我的测试的实现(在 C# 中):

/// <summary>Performs pattern testing on a string to see if it's in a form recognizable as an absolute path.</summary>
/// <param name="test">The string to test.</param>
/// <param name="testExists">If TRUE, this also verifies that the specified path exists.</param>
/// <returns>TRUE if the contents of the passed string are valid, and, if requested, the path exists.</returns>
public bool ValidatePath( string test, bool testExists = false )
{
    bool result = !string.IsNullOrWhiteSpace(test);
    string 
        drivePattern = /* language=regex */ 
           @"^(([A-Z]:(?:\.{1,2}[\/\\]|[\/\\])?)|([\/\\]{1,2}|\.{1,2}[\/\\]))?",
        pattern = drivePattern + /* language=regex */ 
           @"([^\x00-\x1A|*?\t\v\f\r\n+\/,;""'`\\:<>=[\]]+[\/\\]?)+$";
    result &= Regex.IsMatch( test, pattern, RegexOptions.ExplicitCapture );
    pattern = drivePattern + /* language=regex */
        @"(([^\/\\. ]|[^\/. \\][\/. \\][^\/. \\]|[\/\\]$)*[^\x00-\x1A|*?\s+,;""'`:<.>=[\]])$";
    result &= Regex.IsMatch( test, pattern, RegexOptions.ExplicitCapture );
    return result && (!testExists || Directory.Exists( test ));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 2021-06-17
    • 2021-08-18
    相关资源
    最近更新 更多