5

Is there anything similar to make.path.relative(base.path, target.path)?

I want to convert full paths into relative paths given a base path (like project's directory).

Adam Ryczkowski
  • 7,592
  • 13
  • 42
  • 68
  • 1
    If target.path is always a child of base.path, you can probably roll your own function easily with basename() and dirname() http://stackoverflow.com/q/2548815/1191259 – Frank Apr 19 '16 at 18:15
  • 1
    @Frank It will not necessarily be true in the future, but it is a good starting point. Thank you! – Adam Ryczkowski Apr 19 '16 at 18:20

2 Answers2

2

Similar, but shorter:

make.path.relative = function(base, target) {
  common = sub('^([^|]*)[^|]*(?:\\|\\1[^|]*)$', '^\\1/?', paste0(base, '|', target))

  paste0(gsub('[^/]+/?', '../', sub(common, '', base)),
         sub(common, '', target))
}

make.path.relative('C:/home/adam', 'C:/home/adam/tmp/R')
#[1] "tmp/R"

make.path.relative('/home/adam/tmp', '/home/adam/Documents/R')
#[1] "../Documents/R"

make.path.relative('/home/adam/Documents/R/Project', '/home/adam/minetest')
#[1] "../../../minetest"

Voodoo regex comes from here.

Community
  • 1
  • 1
eddi
  • 49,088
  • 6
  • 104
  • 155
1

Ok. I wrote the function myself:

make.path.relative<-function(base.path, target.path)
{
  base.s<-strsplit(base.path,'/',fixed=TRUE)[[1]]
  target.s<-strsplit(target.path,'/',fixed=TRUE)[[1]]
  idx<-1
  maxidx<-min(length(target.s),length(base.s))
  while(idx<=maxidx)
  {
    if (base.s[[idx]]!=target.s[[idx]])
      break
    idx<-idx+1
  }
  dotscount<-length(base.s)-idx+1
  ans1<-paste0(paste(rep('..',times=dotscount),collapse='/'))
  if (idx<=length(target.s))
    ans2<-paste(target.s[idx:length(target.s)],collapse='/')
  else
    ans2<-''
  ans<-character(0)
  if (ans1!='')
    ans[[length(ans)+1]]<-ans1
  if (ans2!='')
    ans[[length(ans)+1]]<-ans2
  ans<-paste(ans,collapse='/')
  return(ans)
}

You must first sanitize the paths to make sure that they use the same slash convention. You can use path.cat function from my answer to Function to concatenate paths?

Examples:

> make.path.relative('C:/home/adam', 'C:/home/adam/tmp/R')
[1] "tmp/R"

> make.path.relative('/home/adam/tmp', '/home/adam/Documents/R')
[1] "../Documents/R"

> make.path.relative('/home/adam/Documents/R/Project', '/home/adam/minetest')
[1] "../../../minetest"
Community
  • 1
  • 1
Adam Ryczkowski
  • 7,592
  • 13
  • 42
  • 68