2017-06-23 50 views
0

我需要檢查,如果Windows文件夾名稱可能有效。該文件夾不一定已經存在。它可以是絕對路徑,也可以是相對路徑,也可以位於網絡中的另一臺機器上(通過UNC尋址)。正則表達式匹配文件夾名稱本地(相對和絕對)和在局域網

以下是有效的位置:

[[X:]\]      'Including an empty string. 
\\server name\    'Including \\123.123.123.123\ 

。注意,Windows並接受/,而不是\以及(驗證,在文件瀏覽器中輸入C:/Users)。

位置可以接着是深路徑,並在路徑名有或沒有結束斜線必須終止:

[folder name\]*folder name[\] 

人物/\:*?<>"|沒有可能的服務器名或文件夾名稱中出現。

這可以通過將提供的文本與正則表達式進行匹配來完成。因此,我創建了一個這樣的:

^        'At the beginning of the string must appear 
    (      'either 
     \\{2}     '2 backslashes 
     [^/\\\:\*\?\<\>\|]+ 'followed by a server name 
     (\\|/)    'and a slash, 
    |       'or 
     (     'a sequence of 
      (\.{2})   '2 dots 
      (\\|/)   'followed by a slash 
     )+     'which may occur at least one time 
    |       'or 
     [A-Za-z]    'a drive letter 
     \:     'followed by a colon 
     (\\|/)    'and a slash 
    |       'or 
     (\\|/)    'simply a slash 
    )?      'or nothing at all; 
(       'followed by a sequence of 
    [^/\\\:\*\?\<\>\|]+  'a folder name 
    (\\|/)     'followed by a slash 
)*       'which may occur multiple times 
[^/\\\:\*\?\<\>\|]+   'The last folder needs no final slash 
(\\|/)?      'but may have one. 

下面的函數被調用:

Private Function IsDirValid(sFile As String) As Boolean 
    Dim sPattern As String = "^[^/\\\:\*\?\<\>\|]+(\\|/)" & 
           "|((\.{2})(\\|/))+" & 
           "|[A-Za-z]\:(\\|/)" & 
           "|(\\|/)" & 
          ")?" & 
          "([^/\\\:\*\?\<\>\|]+(\\|/))*" & 
          "[^/\\\:\*\?\<\>\|]+(\\|/)?" 
    Dim oMatch As Match = Regex.Match(sFile, sPattern) 

    'Debug.Print("""" & sFile & """ returns """ & oMatch.Value & """") 

    Return (sFile = oMatch.Value) 
End Function 

這似乎工作不算太糟糕。這些表現都被視爲有效:

path name[/] 
path name/path name/path name[/] 
/path name[/] 
/path name/path name/path name[/] 
../../path name[/] 
../../path name/path name/path name[/] 
c:/path name[/] 
c:/path name/path name/path name/file name[/] 
\\server name/path name[/] 
\\server name\path name\path name\path name[/] 

(我錯過了一些?)

我唯一的問題是現在,每個path name確實允許開頭和結尾的空白。 這是不允許的路徑名稱。但是,「名義」空白是允許的。

當然,我可以

[^/\\\:\*\?\<\>\|\ ][^/\\\:\*\?\<\>\|]*[^/\\\:\*\?\<\>\|\ ] 

更換出現3次的

[^/\\\:\*\?\<\>\|]+ 

這將解決空白問題(測試),但引入了另一個問題:名字需要在現在至少2個字符(當然不可接受)。它變得很難看。

唉,在regex quick reference guide我無法爲我的問題找到合適的量詞。

因此:有沒有更簡潔的方法?

+0

請參閱[在C#中驗證文件夾名稱](https://stackoverflow.com/questions/12688985/validate-folder-name-in-c-sharp),你嘗試['Path.GetInvalidPathChars(path)'] (https://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.110).aspx)?對於UNC路徑,[檢查路徑是UNC路徑還是本地路徑的正確方法是什麼](https://stackoverflow.com/questions/520753)。 –

+0

@WiktorStribiżew:謝謝。您建議使用'GetInvalidPathChars'暗示'[^/\\\:\ * \?\ <\> \ | \] [^/\\\:\ * \?\ <\> \ |] + [^/\\ \:\ * \?\ <\> \ | \]'不正確?如果您發現了一個證明使用該功能的缺陷,請讓我知道。當然,這不是一個非常優雅的野獸。我希望有一種量詞,說「不能以空白開始/結束」。一種宏也會有所幫助。 – Herb

回答

0

一種可能的解決方案,儘管不是太漂亮,是

[^/\\\:\*\?\<\>\|] 

用該構建體的替代:

(([^/\\\:\*\?\<\>\|\ ][^/\\\:\*\?\<\>\|]*[^/\\\:\*\?\<\>\|\ ])|[^/\\\:\*\?\<\>\|\ ]) 

其內容爲:

(1)作爲第一個字符允許不受禁止的字符,但不允許空白,然後允許多個未受禁止的字符(也包括空格),並且作爲最後一個字符允許未受禁止的字符,但不允許w hitespace;

(2)作爲唯一的字符允許不設防字符,但不空格。

OP中的正則表達式被修改了很多,可以從下面的代碼片斷中推斷出來。如果需要,我可以更詳細地寫下來。

要測試你可以使用此功能(在生產代碼,你需要小心的是,正則表達式構造只是一次):

'Test if the provided folder name is potentially valid (it does not need to 
'exist already). 
Private Function IsDirValid(sDir As String) As Boolean 
    'There are two sets of disallowed characters in server, share and folder 
    'names. Leading And trailing whitespace is not allowed, whitespace within 
    'a name is ok. \"" is escaping a single doublequote mark for syntactical 
    'reasons in VB. SLASH is defined just for readability. {DRIVE} and 
    '{LOCALDIR} are used twice each, so they are encoded as well. 
    Const ALLOWBLANKDOT As String = "[^\x00-\x1F/\\\:\*\?\<\>\""\|]" 
    Const FORBIDBLANKDOT As String = "[^\x00-\x1F/\\\:\*\?\<\>\""\|\ \.]" 
    Const SLASH As String = "(\\|/)" 
    Const DRIVE As String = "((\\{2}\?\\)?[A-Za-z]\:)" 
    Const LOCALDIR As String = "({NAME}|\.{1,2}({SLASH}(\.{2}))*)" 

    'Qualify zero-length strings as False. Pathes may be only 260 characters 
    'long, including a terminating NUL character and 12 characters to 
    'specify the short 8.3 DOS name. Because this limit includes also a file 
    'name not evaluated here, at least two characters (for the slash and at 
    'least one file name character) are subtracted also, for a maximum 
    'path length of 245 characters. 
    If sDir.Length = 0 OrElse sDir.Length > 245 Then Return False 

    'The text identifying a single path level is lengthy and appears multiple 
    'times. For clarity, it is presented with {NAME} in a first step, which 
    'is substituted afterwards by an abstraction of which characters can be 
    'used depending on character position. Eventually, the abstractions are 
    'substitued by the proper regex ensuring that names can contain in-name 
    'spaces and dots, but neither leading or trailing spaces nor dots. 
    '{SLASH} is just used for enhanced readability. 
    Dim sPattern As String = "^(\\{2}(\?\\UNC\\)?{NAME}{SLASH}{NAME}" & 
           "|(({DRIVE}{SLASH}?{LOCALDIR}?)" & 
            "|({DRIVE}?{SLASH}?{LOCALDIR}))" & 
           "|{NAME}" & 
          ")?" & 
          "({SLASH}{NAME})*" & 
          "{SLASH}?" 
    sPattern = Replace(sPattern, "{DRIVE}", DRIVE) 
    sPattern = Replace(sPattern, "{LOCALDIR}", LOCALDIR) 
    sPattern = Replace(sPattern, "{NAME}", 
     "(({FORBIDBLANKDOT}{ALLOWBLANKDOT}*{FORBIDBLANKDOT})" & 
     "|{FORBIDBLANKDOT})") 
    sPattern = Replace(sPattern, "{ALLOWBLANKDOT}", ALLOWBLANKDOT) 
    sPattern = Replace(sPattern, "{FORBIDBLANKDOT}", FORBIDBLANKDOT) 
    sPattern = Replace(sPattern, "{SLASH}", SLASH) 

    Dim oMatch As Match = Regex.Match(sDir, sPattern) 

    Debug.Print("""" & sDir & """ returns """ & oMatch.Value & """") 

    Return (sDir = oMatch.Value) 
End Function 

這並捕獲所有的以下的,按Microsoft specification for path names

[/]path name[/] 
[/]path name/path name/path name[/] 
./path name[/] 
./../path name/path name/path name[/] 
../path name[/] 
../../path name/path name/path name[/] 
c: 
c:path name[/] 
c:path name/path name/path name/file name[/] 
c:/path name[/] 
c:/path name/path name/path name/file name[/] 
c:.[/] 
c:./path name[/] 
c:./path name/path name/path name/file name[/] 
c:..[/] 
c:/../path name[/] 
c:/../path name/path name/path name/file name[/] 
\\?\c:path name[/] 
\\server name/share name[/] 
\\server name\share name\path name\path name[/] 
\\?\UNC\server name\share name[/] 

如果有人想出一件更優雅的作品,請讓我知道