2017-06-23 2 views
0

Ich muss überprüfen, ob ein Windows-Ordnername möglicherweise gültig ist. Der Ordner existiert nicht unbedingt schon. Es kann ein absoluter Pfad sein, ein relativer Pfad, oder er kann sich auf einem anderen Rechner im Netzwerk befinden (adressiert über UNC). Regex passenden Ordnernamen lokal (relativ und absolut) und im LAN

Im folgenden gelten Standorte:

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

Beachten Sie, dass Windows nicht akzeptiert / statt \ als auch (zu überprüfen, geben Sie C:/Users in den Datei-Explorer).

Die Lage kann durch einen tiefen Weg beschritten werden und muß mit oder ohne abschließenden Schrägstrich in einem Pfadnamen beenden:

[folder name\]*folder name[\] 

Keiner der Charaktere /\:*?<>"| kann in Servernamen oder Ordnernamen angezeigt.

Dies kann durch Vergleich des angegebenen Textes mit einem regulären Ausdruck erfolgen. So habe ich eine solche:

^        '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. 

Die folgende Funktion aufgerufen wird:

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 

, die nicht allzu schlecht zu funktionieren scheint. Diese Ausdrücke alle als gültig anerkannt:

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[/] 

(Habe ich etwas verpasst?)

Mein einziges Problem ist jetzt, dass jeder path name erlaubt führende und nachfolgende Leerzeichen. Dies ist in Pfadnamen nicht erlaubt. "In-Name" Leerzeichen sind jedoch erlaubt.

Natürlich konnte ich die drei Vorkommen von

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

von

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

ersetzen, die das Leerzeichen Problem (getestet) lösen würde, führt aber ein anderes: die Namen auf sein müssen mindestens 2 Zeichen lang (inakzeptabel natürlich). Und es wird hässlich.

Ach, in der regex quick reference guide konnte ich keinen geeigneten Quantifikator für mein Problem finden.

Thence: Gibt es einen prägnanter Weg?

+0

Siehe [Name des Ordners in C# validieren] (https://stackoverflow.com/questions/12688985/validate-folder-name-in-c-sharp), haben Sie versucht ['Path.GetInvalidPathChars (path)'] (https://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.110).aspx)? Und für den UNC-Pfad, [Was ist der richtige Weg zu überprüfen, ob ein Pfad ein UNC-Pfad oder ein lokaler Pfad ist] (https://stackoverflow.com/questions/520753). –

+0

@ WiktorStribiżew: Danke. Vermutet Ihr Vorschlag, 'GetInvalidPathChars' zu verwenden, dass '[^/\\\: \ * \? \ <\> \ | \] [^/\\\: \ * \? \ <\> \ |] + [^/\\ \: \ * \? \ <\> \ | \] 'ist nicht korrekt? Wenn Sie einen Fehler gefunden haben, der die Verwendung dieser Funktion rechtfertigt, lassen Sie es mich bitte wissen. Natürlich ist es kein wirklich elegantes Biest. Ich habe auf einen Quantor irgendeiner Art gehofft, der besagt, "darf nicht mit Whitespace beginnen/enden". Auch eine Art Makro würde helfen. – Herb

Antwort

0

Eine mögliche Lösung, wenn auch nicht so schön, ist die Substitution von

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

mit diesem Konstrukt:

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

der wie folgt lautet:

(1) als erstes Zeichen ermöglichen Unverbotene Zeichen, aber keine Leerzeichen, dann erlauben mehrere unerbittliche Zeichen (auch Leerzeichen), und als letztes Zeichen erlauben unerbittliche Zeichen, aber nicht w Stundenraum;

oder

(2) als einzige Zeichen unforbidden Zeichen zulassen, aber nicht Leerzeichen.

Die Regex im OP wurde ziemlich geändert, wie aus dem Code-Snippet entnommen werden kann. Bei Bedarf kann ich es detaillierter aufschreiben.

Um zu testen, diese Funktion (in der Produktion Code, den Sie müssen darauf achten, dass der Regex nur einmal aufgebaut ist) verwenden:

'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 

Dies gilt all folgenden fangen, wie pro 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[/] 

Wenn jemand mit einem eleganteren Stück Arbeit, kommt, lassen Sie es mich bitte wissen.

Verwandte Themen