AutoHotkey Community

It is currently May 25th, 2012, 6:27 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 40 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: May 24th, 2007, 4:13 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Last edited by toralf on May 25th, 2007, 11:42 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 4:27 pm 
Offline

Joined: March 19th, 2006, 5:52 am
Posts: 419
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
  }


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 4:33 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
Thanks, updated the first post.

_________________
Ciao
toralf
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 5:58 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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)
}

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 6:22 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 6:53 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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) : ""
}

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 7:38 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Very useful, thank you.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 10:54 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 24th, 2007, 11:14 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 4:43 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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
}

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 8:14 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 8:29 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 9:16 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 9:18 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
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
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 25th, 2007, 9:24 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5346
Location: UK
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).

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 40 posts ]  Go to page 1, 2, 3  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: bbwht, DataLife, tkmmkt and 12 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group