 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Thu May 24, 2007 4:13 pm Post subject: [Func] RelativePath & AbsolutePath |
|
|
Two functions that return the relative path of a Slavepath relative to a Masterpath or the aboslute path of a RelativePath to a AbsolutePath. A separator s allows to adjust for Unix/HTTP paths.
| Code: | RelativePath(MasterPath, SlavePath, s="\")
AbsolutePath(AbsolutPath, RelativePath, s="\") |
Titan and I improved both functions for speed and treatment of hopefully all cases. These cases are
| Quote: | ../data --> the folder data is located one directory higher
./data --> the folder data is located in the same directory
/data --> the folder data is located in the root of the server or drive |
To expand complex paths like "./.././/data/get.html", Titan created a function that recurse.
RelativePath | Code: | RelativePath(MasterPath, SlavePath, s="\"){
len := InStr(MasterPath, s, "", InStr(MasterPath, s . s) + 2) ;get server or drive string length
If SubStr(MasterPath, 1, len ) <> SubStr(SlavePath, 1, len ) ;different server or drive
Return SlavePath ;return absolut path
MasterPath := SubStr(MasterPath, len + 1 ) ;remove server or drive from MasterPath
SlavePath := SubStr(SlavePath, len + 1 ) ;remove server or drive from SlavePath
If InStr(MasterPath, s, "", 0) = StrLen(MasterPath) ;remove last \ from MasterPath if any
StringTrimRight, MasterPath, MasterPath, 1
If InStr(SlavePath, s, "", 0) = StrLen(SlavePath) ;remove last \ from SlavePath if any
StringTrimRight, SlavePath, SlavePath, 1
Loop{
If !MasterPath ;when there is nothing didentical
Return s SlavePath ;return SlavePath in root
If InStr(SlavePath s, MasterPath s){ ;when parts of paths match
If !r ;no relative part yet
r = .%s% ;SlavePath is in the MasterPath
Return r . SubStr(SlavePath,StrLen(MasterPath) + 2) ;return relative path
}Else{ ;otherwise
r .= ".." s ;add relative part
MasterPath := SubStr(MasterPath, 1, InStr(MasterPath, s, "", 0) - 1) ;remove one folder from MasterPath
}
}
}
|
AbsolutePath | Code: | AbsolutePath(AbsolutPath, RelativePath, s="\") {
len := InStr(AbsolutPath, s, "", InStr(AbsolutPath, s . s) + 2) - 1 ;get server or drive string length
pr := SubStr(AbsolutPath, 1, len) ;get server or drive name
AbsolutPath := SubStr(AbsolutPath, len + 1) ;remove server or drive from AbsolutPath
If InStr(AbsolutPath, s, "", 0) = StrLen(AbsolutPath) ;remove last \ from AbsolutPath if any
StringTrimRight, AbsolutPath, AbsolutPath, 1
If InStr(RelativePath, s, "", 0) = StrLen(RelativePath) ;remove last \ from RelativePath if any
StringTrimRight, RelativePath, RelativePath, 1
If InStr(RelativePath, s) = 1 ;when first char is \ go to AbsolutPath of server or drive
AbsolutPath := "", RelativePath := SubStr(RelativePath, 2) ;set AbsolutPath to nothing and remove one char from RelativePath
Else If InStr(RelativePath,"." s) = 1 ;when first two chars are .\ add to current AbsolutPath directory
RelativePath := SubStr(RelativePath, 3) ;remove two chars from RelativePath
Else { ;otherwise
StringReplace, RelativePath, RelativePath, ..%s%, , UseErrorLevel ;remove all ..\ from RelativePath
Loop, %ErrorLevel% ;for all ..\
AbsolutPath := SubStr(AbsolutPath, 1, InStr(AbsolutPath, s, "", 0) - 1) ;remove one folder from AbsolutPath
}
Return, pr . AbsolutPath . s . RelativePath ;concatenate server + AbsolutPath + separator + RelativePath
}
|
_________________ Ciao
toralf 
Last edited by toralf on Fri May 25, 2007 11:42 pm; edited 3 times in total |
|
| Back to top |
|
 |
TheIrishThug
Joined: 19 Mar 2006 Posts: 370
|
Posted: Thu May 24, 2007 4:27 pm Post subject: |
|
|
Works nicely unless you have the following:
| Quote: | Path1 = \\server.com\user\Files\Docs\Code\AHK\SciTEDirector\includes
Path2 = \\server.com\user123\Files\Docs\Code\AHK\SmartGui\no_commit\icons_dev |
But it's an easy fix. Just break the loop when you find the first folder that doesn't match.
| Code: | Path1 = \\server.com\user\Files\Docs\Code\AHK\SciTEDirector\includes
Path2 = \\server.com\user\Files\Docs\Code\AHK\SmartGui\no_commit\icons_dev
MsgBox, % RelativePath(Path1, Path2)
MsgBox, % RelativePath(Path2, Path1)
Path2 = \\server.com\user123\Files\Docs\Code\AHK\SmartGui\no_commit\icons_dev
MsgBox, % RelativePath(Path1, Path2)
MsgBox, % RelativePath(Path2, Path1)
Return
;return the relative path of Slavepath to Masterpath
RelativePath(MasterPath, SlavePath){
;remove last \ if there are any
MasterPath := RegExReplace(MasterPath, "\\$")
SlavePath := RegExReplace(SlavePath, "\\$")
;create arrays
StringSplit, MasterPath, MasterPath, \
StringSplit, SlavePath, SlavePath, \
;sort out equivalent portions
Loop, %MasterPath0%
If (MasterPath%A_Index% = SlavePath%A_Index%)
Same := A_Index
Else
Break
;build relative path
Loop, % MasterPath0 - Same
RelativePath .= "..\"
Loop, % SlavePath0 - Same {
ID := Same + A_Index
RelativePath .= SlavePath%ID% "\"
}
Return RelativePath
} |
|
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Thu May 24, 2007 4:33 pm Post subject: |
|
|
Thanks, updated the first post. _________________ Ciao
toralf  |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Thu May 24, 2007 5:58 pm Post subject: |
|
|
You can do this with regex too:
| Code: | RelPath(root, dir) {
ex := RegExReplace(dir, "(\\+[^\\]+)", "($1)?")
StringReplace, ex, ex, \, \\, All
pos := InStr(root, rel := RegExReplace(root, ex))
Return, RegExReplace(rel, "\\[^\\]+", "..\") . SubStr(dir, pos + 1)
} |
_________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Thu May 24, 2007 6:22 pm Post subject: |
|
|
Unfortunately the regex version doesn't work for all cases. Test code follows | Code: | Path1 = \\server.com\user\Files\Docs\Code\AHK\SciTEDirector\includes
Path2 = \\server.com\user\Files\Docs\Code\AHK\SmartGui\no_commit\icons_dev
MsgBox, % "1: " RelativePath(Path1, Path2) "`n2: " RelPath(Path1, Path2)
MsgBox, % "1: " RelativePath(Path2, Path1) "`n2: " RelPath(Path2, Path1)
MsgBox, % "1: " RelativePath(Path1, Path1) "`n2: " RelPath(Path1, Path1) ;< supposed to be empty
Path1 = \\server.com\user\Files\Docs\Code\AHK\SciTEDirector\includes
Path2 = \\server.com\user\Files123\Docs\Code\AHK\SmartGui\no_commit\icons_dev
MsgBox, % "1: " RelativePath(Path1, Path2) "`n2: " RelPath(Path1, Path2)
MsgBox, % "1: " RelativePath(Path2, Path1) "`n2: " RelPath(Path2, Path1)
MsgBox, % "1: " RelativePath(Path1, Path1) "`n2: " RelPath(Path1, Path1) ;< supposed to be empty
Return
|
_________________ Ciao
toralf  |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Thu May 24, 2007 6:53 pm Post subject: |
|
|
That was just an example, proper regex would be:
| Code: | RelPath(root, dir) {
Loop, Parse, dir, \
If A_LoopField
ex .= "(\\" . (d ? "\\" : "") . A_LoopField, ey .= "\b)?", d := 0
Else d = 1
Return, (pos := InStr(root, rel := RegExReplace(root, ex . ey)))
and rel ? RegExReplace(rel, "\\[^\\]+", "..\") . SubStr(dir, pos + 1) : ""
} |
_________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Thu May 24, 2007 7:38 pm Post subject: |
|
|
Very useful, thank you. _________________
 |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Thu May 24, 2007 10:54 pm Post subject: |
|
|
Thanks for the update. It seems to work.
I tested both for performance, the regex version is slightly slower.
Since the normal code is easier to maintain and change to specific needs, I'll stick with it. Thanks again for showing the alternative. _________________ Ciao
toralf  |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Thu May 24, 2007 11:14 pm Post subject: |
|
|
A benchmark shows that regex is faster albeit slight fluctuations. However your code is better as it doesn't have the regex overhead, which is only justified for several thousands of calls. Thanks for creating this, it'll be useful to me. _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Fri May 25, 2007 4:43 pm Post subject: |
|
|
Sometimes you need to get the absolute path from a relative one, this function does just that:
| Code: | MsgBox, % RelToAbs("\\server.com\user\Files\Docs\Code\AHK\SmartGui\no_commit\icons_dev", "..\..\..\SciTEDirector\includes\")
MsgBox, % RelToAbs("http://example.com/info/sec/", "../data/get.html", "/")
MsgBox, % RelToAbs("http://example.com/info/sec/", "/data/get.html", "/")
RelToAbs(root, dir, s = "\") {
pr := SubStr(root, 1, len := InStr(root, s, "", InStr(root, s . s) + 2) - 1)
, root := SubStr(root, len + 1), off := 0
If InStr(root, s, "", 0) = StrLen(root)
StringTrimRight, root, root, 1
If InStr(dir, s, "", 0) = StrLen(dir)
StringTrimRight, dir, dir, 1
Loop, Parse, dir, %s%
If InStr(A_LoopField, "..") = 1
root := SubStr(root, 1, InStr(root, s, "", 0) - 1)
Else If A_LoopField =
root := "", dir := SubStr(dir, 2)
StringReplace, dir, dir, ..%s%, , All
Return, pr . root . s . dir
} |
_________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Fri May 25, 2007 8:14 pm Post subject: |
|
|
This would be my version for that problem: | Code: | AbsolutePath(root, dir, s = "\") {
;remove last \ if there are any
root := RegExReplace(root, "\Q" s "\E$")
dir := RegExReplace(dir, "\Q" s "\E$")
;remove first \ of relativepath if there is one
dir := RegExReplace(dir, "^\Q" s "\E")
;create arrays
StringSplit, root, root, %s%
StringSplit, dir, dir, %s%
;combine to new absolute path
Count = 0
Loop % Root0 + dir0 {
If (A_Index <= dir0) {
ID := Dir0 - A_Index + 1
If (Dir%ID% <> "..")
AbsolutePath := Dir%ID% . s . AbsolutePath
Else Count++
}Else{
ID := Root0 + Dir0 - A_Index + 1 - Count
If ID > 0
AbsolutePath := Root%ID% . s . AbsolutePath
Else Break
}
}
Return RegExReplace(AbsolutePath, "\Q" s "\E$") ;remove last \
}
| BTW: Our solutions differ for the third test example in your code. Which one is correct? _________________ Ciao
toralf  |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Fri May 25, 2007 8:29 pm Post subject: |
|
|
| toralf wrote: | | Our solutions differ for the third test example in your code. Which one is correct? | My one is correct, at least for URI standards. Besides, I thought you never liked regex. _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Fri May 25, 2007 9:16 pm Post subject: |
|
|
I do like RegEx, but only when it is fast and necessary.
My code for the absolute path is much slower then yours. I currently look for speed ups. _________________ Ciao
toralf  |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3842 Location: Bremen, Germany
|
Posted: Fri May 25, 2007 9:18 pm Post subject: |
|
|
| Titan wrote: | | My one is correct, at least for URI standards. Besides, I thought you never liked regex. | Does a / infront mean that it is the root of the server? _________________ Ciao
toralf  |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Fri May 25, 2007 9:24 pm Post subject: |
|
|
| toralf wrote: | | Does a / infront mean that it is the root of the server? | Yes, / means root, ../ is one level up and ./ is the current directory (which neither of our functions cover). _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|