jpmc26
jpmc26

Reputation: 29876

How can I check whether a path is a child of another path?

Say I have the following path, which we will call the "base":

C:\my\dir

and these two other paths, which we will call paths "A" and "B" respectively:

C:\my\dir\is\a\child
C:\not\my\dir

Obviously, the base must be a directory for this to make any sense. Path A is inside the base at some arbitrary depth, and Path B is not inside base at all. Paths A and B could be files or directories; it really doesn't matter.

How can I detect that Path A is inside base and Path B is not? Preferably, we could avoid directly messing with the strings to do this.

Edit:

The case of the following path has come to my attention:

C:\my\dir2\child

At the moment, the proposed solutions all result in a false positive in this case, but the solution should be able to distinguish. I think this kind of thing is why I was concerned about doing this via string manipulation/comparison directly. What would be the most effective way of dealing with this?

Additionally, I don't want to make any assumptions about whether the base path does or does not contain a trailing directory separator.

Upvotes: 1

Views: 167

Answers (3)

mjolinor
mjolinor

Reputation: 68263

There's this: (Edited to allow for specifying a base path with or without a trailing backslash)

$basepath = 'C:\my\dir'

$patha = 'C:\my\dir\is\a\child'
$pathb = 'C:\not\my\dir'
$pathc = 'C:\my\dir2\child'

$patha -like "$($basepath.trim('\'))\*"
$pathb -like "$($basepath.trim('\'))\*"
$pathc -like "$($basepath.trim('\'))\*"
True
False
False

Upvotes: 1

vonPryz
vonPryz

Reputation: 24071

This is a case of text/pattern matching, so regex works fine.

PS C:\> $base = "^"+[regex]::escape('C:\my\dir')+".*`$"
PS C:\> $base
^C:\\my\\dir.*$
PS C:\> "C:\my\dir\is\a\child" -match $base
True
PS C:\> "C:\not\my\dir" -match $base
False

The regex ^C:\\my\\dir.+$ looks for start ^, followed by string literal (handily escaped with [regex]::escape()) that is the base path and finally anything until end: .*$.

Edit:

To handle the commented case, just add backslash to base dir like so,

PS C:\> $base = "^"+[regex]::escape('C:\my\dir\')+".*`$"
PS C:\> $base
^C:\\my\\dir\\.*$
PS C:\> "C:\my\dir\is\a\child" -match $base
True
PS C:\> "C:\not\my\dir" -match $base
False
PS C:\> "C:\my\dir2\child" -match $base
False

Upvotes: 1

Sergey Kolodiy
Sergey Kolodiy

Reputation: 5899

In .NET, path is simply a string. You have static System.IO.Path class that works with strings and returns paths as a strings too.

So, in this terms, I would define pathA as a child of pathB as simple as following:

bool child = pathA.StartsWith(pathB, StringComparison.OrdinalIgnoreCase);

Upvotes: 3

Related Questions