模式匹配路径+文件(UNC?)

时间:2014-04-08 21:22:54

标签: c# regex pattern-matching unc

我正在使用C#和Visual Studio 2010.我只是尝试匹配一个字符串(在这种情况下是一个路径)并创建一个模式,这将帮助我弄清楚它是否是一个有效的模式或不。以下示例由仲裁示例组成,但它们包含

所以我试图创建一个匹配UNC路径的模式,该路径以字符串形式出现。例如:

"\\\\Apple-butter27\\AliceFakePlace\\SomeDay\\Grand100\\Some File Name Stuff\\Yes these are fake words\\One more for fun2000343\\myText.txt"

上面是我尝试模式匹配的文件路径的示例。我试图将它与这种模式相匹配:

@"\\\\[a-zA-Z0-9-]+\\\w+\\\w+\\\w+\\((\w+)*(\s+)*)*\\((\w+)*(\s+)*)*\\((\w+)*(\s+)*)*\\w+\.txt";

我保证的是在我到达我的文件之前会有7个文件夹。我必须为几乎所有细分市场寻找空格,字母和数字的组合。

我确实尝试通过匹配小位来开始,比如我的第一次迭代测试我试过这个作为我的模式:

@"\\\\";

这是有效的,因为它会匹配前几个字符,但如果我将其添加到它:

@"\\\\[a-zA-Z0-9-]+";

失败了。所以我想也许是因为琴弦导致它加倍,所以我可能需要加倍我的" \"所以我再次尝试了8" \"单独,但失败了。

我之前模式的目标是匹配" \\\\ Apple-butter27"

我一直在寻找谷歌和整个网站,但我找到的模式匹配UNC的东西都不是我的问题。

如果有人能告诉我这个模式我做错了什么,我真的很感激。至少是一个起点,因为我知道它很长,可能会是一个非常复杂的...但如果有人可以指出一般的事情是错误的。

虽然它是非字符串状态的路径,但它看起来像这样:

\\Apple-butter27\AliceFakePlace\SomeDay\Grand100\Some File Name Stuff\Yes these are fake words\One more for fun2000343\myText.txt

我很想尝试与UNC路径进行模式匹配,所以它开始让我感到困惑,所以如果有人能照亮我的路,我会非常感激。

我使用Regex的 .Success 功能查看模式是否匹配,如果匹配成功或失败,我只是打印一条消息。我的主要关注点是模式,除非在将路径作为解决方案的字符串以外的其他方面有一些很好的见解。

3 个答案:

答案 0 :(得分:6)

不需要正则表达式

或者,使用System.Uri类的内置解析:

foreach (var path in new [] { @"C:\foo\bar\", @"\\server\bar" })
{
    var uri = new Uri(path);

    if (uri.IsUnc)
    {
        Console.WriteLine("Connects to host '{0}'", uri.Host);
    }
    else
    {
        Console.WriteLine("Local path");
    }
}

打印:

  

本地路径
  连接到主机'服务器'

如果你想与扩展名匹配,不要重新发明轮子,请使用Path.GetExtension

var path = "\\some\really long and complicated path\foo.txt";
var extensionOfPath = Path.GetExtension(path);

if (string.Equals(".txt", extensionOfPath, StringComparison.CurrentCultureIgnoreCase))
{
    Console.WriteLine("It's a txt");
}
else
{
    Console.WriteLine("It's a '{0}', which is not a txt", extensionOfPath);
}

通常,我建议您在解决问题时避免跳到正则表达式。首先问问自己是否有其他人为您解决了问题(example for HTML)。很好地讨论了为什么正则表达式在CodingHorror和(不太严肃)on xkcd上有错误的代表。

正则表达式版本

如果您一直在使用正则表达式,我维护它不是最好的工具,可以做到。使用间距和注释来确保代码可读。

string input = @"\\Apple-butter27\AliceFakePlace\SomeDay\Grand100\Some File Name Stuff\Yes these are fake words\One more for fun2000343\myText.txt";
Regex regex = new Regex(@"
    ^
    (?:
        # if server is present, capture to a named group
        # use a noncapturing group to remove the surrounding slashes
        # * is a greedy match, so it will butt up against the following directory search
        # this group may or may not occur, so we allow either this or the drive to match (|)
        (?:\\\\(?<server>[^\\]*)\\)
        # if there is no server, then we best have a drive letter
        |(?:(?<drive>[A-Z]):\\)
    )
    # then we have a repeating group (+) to capture all the directory components
    (?:
        # each directory is composed of a name (which does not contain \\)
        # followed by \\
        (?<directory>[^\\]*)\\
    )+
    # then we have a file name, which is identifiable as we already ate the rest of
    # the string.  So, it is just all non-\\ characters at the end.
    (?<file>[^\\]*)
    $", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

var matches = regex.Match(input).Groups;

foreach (var group in regex.GetGroupNames())
{
    Console.WriteLine("Matched {0}:", group);
    foreach (var value in matches[group].Captures.Cast<Capture>())
    {
        Console.WriteLine("\t{0}", value.Value);
    }
}

打印

Matched server:
        Apple-butter27
Matched drive:
Matched directory:
        AliceFakePlace
        SomeDay
        Grand100
        Some File Name Stuff
        Yes these are fake words
        One more for fun2000343
Matched file:
        myText.txt

我现在只是猜...

听起来你有某种应用程序调用它所在的目录并在其下构建一个多层结构。如下所示:

C:\
  root directory for the application\
    site name\
      date of work\
        project name\
          bar\
            actual.txt
            files.txt

你正在寻找实际的文件,或者不是,我不知道。无论哪种方式,我们都知道C:\root directory\并认为它可能有实际文件。然后我们可以获取目录树并枚举以查找实际文件:

var diRoot = new DirectoryInfo(@"C:\drop");

var projectDirectories = FindProjects(diRoot);

// get all of the files in all of the project directories of type .txt
var projectFiles = projectDirectories.SelectMany(di => di.GetFiles("*.txt"));

// projectFiles now contains:
//  actual.txt
//  files.txt

private static IEnumerable<DirectoryInfo> FindProjects(DirectoryInfo cDir, int depth = 0)
{
    foreach (var di in cDir.GetDirectories())
    {
        // assume projects are three levels deep
        if (depth == 3)
        {
            // it's a project, so we can return it
            yield return di;
        }
        else
        {
            // pass it through, return the results
            foreach (var d in FindProjects(di, depth + 1))
                yield return d;
        }
    }
}

由于我们没有对路径进行字符串操作,因此我们可以透明地处理本地和UNC路径。

答案 1 :(得分:1)

如果您正在尝试检查路径是否存在,则可以执行以下操作:

FileInfo fi = new FileInfo(@""\\\\Apple-butter27\\AliceFakePlace\\SomeDay\\Grand100\\Some File Name Stuff\\Yes these are fake words\\One more for fun2000343\\myText.txt"");
bool exists = fi.Exists;

但是如果您在运行验证时无法访问这些路径,则可以使用此模式查找\\ Apple-butter27:

const string rootPattern = @"(\\\\[a-zA-Z-_0-9]+)";

const RegexOptions regexOptions = RegexOptions.Compiled;

var regex = new Regex(rootPattern, regexOptions);

            foreach (Match match in regex.Matches(fileName))
            {
                if (match.Success && match.Groups.Count >= 1 )
                {
                    shareRoot = match.Groups[0].Value;
                }
            }

我尝试了这种模式,而0组给了我正确的\\ Apple-butter27 您将不得不在[括号]中添加其他字符,例如可能是'。'。

答案 2 :(得分:0)

虽然我不同意System.Uri的使用(可能是你需要的工具);我假设我们必须遵守匹配正则表达式的模式:

        const string tString = "\\\\Apple-butter27\\AliceFakePlace\\SomeDay\\Grand100\\Some File Name Stuff\\Yes these are fake words\\One more for fun2000343\\myText.txt";
        const string tRegexPattern = @"(\\\\)?((?<Folder>[a-zA-Z0-9- ]+)(\\))";
        const RegexOptions tRegexOptions = RegexOptions.Compiled;

        Regex tRegex = new Regex(tRegexPattern, tRegexOptions);

        Console.WriteLine(tString);

        if (tRegex.Matches(tString).Count == 7)
        {
            foreach (Match iMatch in tRegex.Matches(tString))
            {
                if (iMatch.Success && iMatch.Groups["Folder"].Length > 0)
                {
                    Console.WriteLine(iMatch.Groups["Folder"].Value);
                }
            }
        }
        else
            throw new Exception("String did not have a path of depth 7");

虽然您可以强制正则表达式仅匹配7个组,但Regex实际上是为模式匹配而设计的,而不是&#39; loopy-logic&#39;。

?&lt; Folder&gt;只有在跟着分隔符后才会匹配组(尾随&#39; \&#39;),因此它只匹配文件夹模式而不匹配文件或文件扩展名。