Regex windows路径验证器



我试图为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>");
});

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

让我们从一些观察开始:

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

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

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

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

  • "启动"部分,匹配驱动器号、冒号和最多2斜线(向前或向后)
  • 第一种选择-点、斜线、反斜线或空格,带有负前瞻-在以上字符(见第1点)
  • 第二种选择——第2点提到的字符
  • 以上两种备选方案都可以出现多次(+量词)

因此正则表达式如下:

  • ^-字符串的开头
  • (?:[a-z]:)?-驱动器号和冒号,可选
  • [/\]{0,2}-反斜杠或斜线,介于0到2倍之间
  • (?:-非捕获组的启动,由于+而需要后面的量词。
    • [./\ ]-第一个备选方案
    • (?![./\n])-否定前瞻-"禁止"字符
  • |-或者。
    • [^<>:"|?*./\ n]-第二种选择
  • )+-非捕获组结束,可能发生多次
  • $-字符串的末尾

如果尝试分别匹配每个路径,请仅使用i选项。

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

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

注意:我认为!也应该被视为禁用性格如果您同意,请将其添加到第二个备选方案中,例如*之后。

这可能适用于您:^(?!.*[\/]s+)(?!(?:.*s|.*.|W+)$)(?:[a-zA-Z]:)?(?:(?:[^<>:"|?*n])+(?://|/|\\|\)?)+$

你在这里有一个演示

解释:

^
(?!.*[\/]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

$

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

我无法想出一个可行的REGEX,无论有没有look ahead和look behinds,都能完成这项工作,但我可以用两个来完成,没有任何look aheads或-behinds

不过,请注意,连续的相对路径(即"..\..\folder\file.exe")不会通过此模式(尽管在字符串的开头使用"..\"或".\")。斜杠前后或行尾的句点和空格,以及根据Microsoft的短文件名规范不允许使用的任何字符都将失败:https://learn.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|*?vrnf+/,;"'`\:<>=[]]+[/\]?)+
$   (?# <- 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. #)

这验证了在路径体中,没有出现多个句点、多个斜杠、句点斜杠、空格斜杠、斜杠空格或斜杠句点,并且路径没有以无效字符结束。令人烦恼的是,我不得不重新验证<root>组,因为它是允许其中一些组合的地方(即".\"、"\\"one_answers"..\"),我不希望这些组合使模式无效。

下面是我的测试(在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|*?tvfrn+/,;""'`\:<>=[]]+[/\]?)+$";
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 ));
}

最新更新