1

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.

jpmc26
  • 28,463
  • 14
  • 94
  • 146

3 Answers3

3

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);
Sergey Kolodiy
  • 5,829
  • 1
  • 36
  • 58
  • 2
    Hm. It occurs to me that this would give a false positive if my base were `C:\my\dir` and my path to test were `C:\my\dir2\child`. My apologies for not raising this specific case in my question, but I believe it's reasonable to expect a solution to cover it. – jpmc26 Apr 01 '14 at 18:50
  • Indeed! To be even more accurate, we should consider such corner-case when your path is something like `C:\dir1\..\dir2`, which is equivalent to `C:\dir2`. Obviously, my solution will fail in this case too. – Sergey Kolodiy Apr 01 '14 at 19:14
  • I think that situation is solvable by ensuring we have an absolute path. The other issue is probably solvable by doing some kind of conditional adding of a trailing slash. (Since we're looking for children, they would necessarily contain the directory separator.) I was hoping to avoid all that manual manipulation, though, and find something simpler. It may not be avoidable, though. – jpmc26 Apr 01 '14 at 20:09
  • @jpmc26: The path normalization from [this question](http://stackoverflow.com/q/2281531) may be useful: `[IO.Path]::GetFullPath( (New-Object Uri $path).LocalPath ).TrimEnd( @([IO.Path]::DirectorySeparatorChar,[IO.Path]::AltDirectorySeparatorChar) ) + [IO.Path]::DirectorySeparatorChar` – Emperor XLII Apr 05 '14 at 23:29
1

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
vonPryz
  • 22,996
  • 7
  • 54
  • 65
1

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
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • `$basepath = 'C:\my\dir\'`, then `'C:\my\dir\is\a\child' -like "$basepath\*"` returns `False`. =( – jpmc26 Apr 06 '14 at 18:51
  • That's because you've changed how your basepath is specified from your original post by adding the trailing backslash. Edited answer to account for changing requirements. – mjolinor Apr 06 '14 at 19:09
  • My post says, "Additionally, I don't want to make any assumptions about whether the base path does or does not contain a trailing directory separator." – jpmc26 Apr 06 '14 at 19:17