No regex required
Alternatively, use the built in parsing of the System.Uri
class:
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");
}
}
Prints:
Local Path
Connects to host 'server'
And if you are trying to match against the extension, don't re-invent the wheel, use 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);
}
Generally, I am trying to recommend you avoid jumping to regex when solving a problem. Ask yourself first if someone else has solved the problem for you (example for HTML). There is good discussion of why regex has a bad rep on CodingHorror and (less seriously) on xkcd.
Regex Version
If you are bent on using Regex, which I maintain is not the best tool for the job, it can be done. Use spacing and comments to ensure your code is readable.
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);
}
}
Prints
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
I'm just guessing now...
It sounds like you have some sort of application which calls a directory it's home and builds a multi-layer structure underneath. Something like the following:
C:\
root directory for the application\
site name\
date of work\
project name\
bar\
actual.txt
files.txt
And you are looking for the actual files, or not, I can't tell. Either way, we know about C:\root directory\
and think it may have actual files. We can then take the directory tree and enumerate to find the actual files:
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;
}
}
}
And since we are not doing string manipulation of paths, we can handle local and UNC paths transparently.