Cetak jalur relatif

15

Deskripsi

Diberikan jalur sumber dan jalur tujuan, output jalur relatif ke tujuan sehubungan dengan sumber.

Aturan

  1. Input dapat berasal dari stdin atau sebagai argumen untuk program / fungsi.

  2. Jalur gaya Windows dan Unix harus didukung.

  3. Jalur keluaran dapat menggunakan /dan / atau \untuk pemisah jalur (pilihan Anda dan kombinasi keduanya OK).

  4. Anda dapat mengasumsikan jalur relatif dimungkinkan.

  5. Penggunaan program eksternal, fungsi perpustakaan atau built-in yang dibuat untuk menghitung jalur relatif dilarang (misalnya Python os.path.relpath)

  6. Ini adalah

    Edit: Aturan baru dari komentar.

  7. Jalur relatif harus jalur relatif sesingkat mungkin.

  8. Asumsikan jalur tujuan berbeda dari jalur sumber.

Contoh 1

# In
/usr/share/geany/colorschemes
/usr/share/vim/vim73/ftplugin

# Out
../../vim/vim73/ftplugin

Contoh 2

# In
C:\Windows\System32\drivers
C:\Windows\System32\WindowsPowerShell\v1.0

# Out
..\WindowsPowerShell\v1.0
Rynant
sumber
Mengenai aturan # 3 - apakah campuran itu ok? Misalnya ../../vim\vim73\ftplugin.
Duncan Jones
1
Apakah kita harus mengembalikan jalur relatif terpendek atau tidak apa-apa untuk menghasilkan jalur apa pun?
Howard
@Uncunc Ya, campuran ok.
Rynant
1
@Howard, itu pasti jalur relatif terpendek.
Rynant
bukankah seharusnya contoh pertama ../vim/vim73/ftplugin?
Martijn

Jawaban:

2

CJam, 46 byte

ll]{'\/'/f/:~}/W{)__3$=4$@==}g@,1$-"../"*o>'/*

Cobalah online.

Contohnya

$ echo '/usr/share/geany/colorschemes
> /usr/share/vim/vim73/ftplugin' | cjam path.cjam; echo
../../vim/vim73/ftplugin
$ echo 'C:\Windows\System32\drivers
> C:\Windows\System32\WindowsPowerShell\v1.0' | cjam path.cjam; echo
../WindowsPowerShell/v1.0

Bagaimana itu bekerja

ll]         " Read two lines from STDIN and wrap them in an array.                       ";
{           " For each line:                                                             ";
  '\/       " Split by “\”.                                                              ";
  '/f/      " Split each chunk by “/”.                                                   ";
  :~        " Flatten the array of chunks.                                               ";
}/          "                                                                            ";
W           " Push -1 (accumulator).                                                     ";
{           "                                                                            ";
  )__       " Increment and duplicate twice.                                             ";
  3$=       " Extract the corresponding chunk from the first line.                       ";
  4$@=      " Extract the corresponding chunk from the second line.                      ";
  =         " If the are equal,                                                          ";
}g          " repeat the loop.                                                           ";
@,          " Rotate the array of chunks of the first line on top and get its length.    ";
1$-         " Subtract the value of the accumulator.                                     ";
"../"*o     " Print the string “../” repeated that many times.                           ";
>           " Remove all chunks with index less than the accumulator of the second line. ";
'/*         " Join the chunks with “/”.                                                  ";
Dennis
sumber
1
Ia memiliki bug. Coba /aa/xdengan /ab/y.
jimmy23013
@ user23013: Diperbaiki.
Dennis
2

Bash + coreutils, 116

Berikut ini skrip shell untuk membuat bola bergulir. Cukup yakin akan ada jawaban yang lebih pendek:

n=`cmp <(echo $1) <(echo $2)|grep -Po "\d+(?=,)"`
printf -vs %`grep -o /<<<${1:n-1}|wc -l`s
echo ${s// /../}${2:n-1}

Keluaran:

$ ./rel.sh /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../vim/vim73/ftplugin
$ ./rel.sh /usr/share/geany/colorschemes/ /usr/share/vim/vim73/ftplugin/
../../vim/vim73/ftplugin/
$ ./rel.sh /usr/share/vim/vim73/ftplugin /usr/share/geany/colorschemes
../../geany/colorschemes
$ 

Catatan tidak ada cara bagi skrip untuk mengetahui apakah string ftpluginadalah file atau direktori. Anda dapat secara eksplisit menyediakan direktori dengan menambahkannya /seperti pada contoh di atas.

Tidak akan menangani jalur yang berisi spasi putih atau karakter lucu lainnya. Tidak yakin apakah itu persyaratan atau tidak. Hanya beberapa kutipan tambahan akan dibutuhkan.

Trauma Digital
sumber
2

Javascript (E6) 104

Edit lansiran yang ditambahkan untuk keluaran

R=(s,d)=>alert(s.split(x=/\/|\\/).map(a=>a==d[0]?d.shift()&&'':'../',d=d.split(x)).join('')+d.join('/'))

Tidak disatukan

R (s,d) => // a single espression is returned, no {} or () needed
  s.split(x=/\/|\\/) // split string at / or \, save regexp in X for later
  .map( // create a new array from s
     a => a == d[0] // check if current of s and d equals
          ? d.shift() && '' // map to '' and cut 1 element of d
          : '../', // else map to '../'
     d=d.split(x)) // second param of map is useless, so split d here
  .join('')+d.join('/') // join map and concat to rest of d adding separators

Uji

R('C:\\Windows\\System32\\drivers','C:\\Windows\\System32\\WindowsPowerShell\\v1.0')

../WindowsPowerShell/v1.0

R('/usr/share/geany/colorschemes','/usr/share/vim/vim73/ftplugin')

../../vim/vim73/ftplugin

edc65
sumber
2

Ruby> = 1.9, 89 94 karakter

$;=/\\|\//
a,b=$*.map &:split
puts"../"*(a.size-r=a.index{a[$.+=1]!=b[$.]}+1)+b[r..-1]*?/

Masukan melalui argumen baris perintah. Bekerja untuk jalur gaya UNIX dan Windows, termasuk jalur dengan nama folder berulang:

$ ruby relpath.rb /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../../vim/vim73/ftplugin
$ ruby relpath.rb 'C:\Windows\System32\drivers' 'C:\Windows\System32\WindowsPowerShell\v1.0'
../WindowsPowerShell/v1.0
$ ruby relpath.rb /foo/bar/foo/bar /foo/qux/foo/bar
../../../qux/foo/bar
Ventero
sumber
2

J - 63 char

Fungsi mengambil jalur lama di sebelah kiri dan jalur baru di sebelah kanan.

}.@;@(c=.c&}.`(,~(<'/..')"0)@.(~:&{.))&('/'<;.1@,'\/'&charsub)~

Solusi ini datang dalam tiga bagian, terlihat seperti post@loop&pre~. Dijelaskan oleh ledakan:

post @ loop & pre ~   NB. the full golf
                  ~   NB. swap the arguments: new on left, old on right
            & pre     NB. apply pre to each argument
       loop           NB. run the recursive loop on both
post @                NB. apply post to the final result

'/'<;.1@,'\/'&charsub  NB. pre
         '\/'&charsub  NB. replace every \ char with /
'/'     ,              NB. prepend a / char
   <;.1@               NB. split string on the first char (/)

c=.c&}.`(,~(<'/..')"0)@.(~:&{.)  NB. loop
                      @.(~:&{.)  NB. if the top folders match:
    &}.                          NB.   chop off the top folders
   c                             NB.   recurse
       `                         NB. else:
           (<'/..')"0            NB.   change remaining old folders to /..
         ,~                      NB.   append to front of remaining new folders
c=.                              NB. call this loop c to recurse later

}.@;  NB. post
   ;  NB. turn the list of folders into a string
}.@   NB. chop off the / in the front

Perhatikan bahwa kami menambahkan garis depan /ke setiap jalur sebelum dipisah, sehingga kami menangani jalur gaya Windows dengan membuatC: "folder". Ini menghasilkan folder kosong di awal lintasan Unix-style, tapi itu selalu dihapus oleh loop.

Lihat dalam aksi:

   NB. you can use it without a name if you want, we will for brevity
   relpath =. }.@;@(c=.c&}.`(,~(<'/..')"0)@.(~:&{.))&('/'<;.1@,'\/'&charsub)~
   '/usr/share/geany/colorschemes' relpath '/usr/share/vim/vim73/ftplugin'
../../vim/vim73/ftplugin
   'C:\Windows\System32\drivers' relpath 'C:\Windows\System32\WindowsPowerShell\v1.0'
../WindowsPowerShell/v1.0

Anda juga dapat mencoba sendiri di tryj.tk .

algoritme hiu
sumber
2

Bash, 69 66

Saya tidak memposting yang ini karena saya pikir seseorang harus dapat melakukannya dengan lebih baik. Namun ternyata itu tidak mudah.

sed -r 'N;s/(.*[/\])(.*)\n\1/\2\n/'|sed '1s/[^/\]*/../g;N;s!\n!/!'

Nmembuat sedpertandingan dua baris bersama. Ekspresi pertama menghapus awalan umum yang diakhiri dengan /atau \. Ekspresi kedua menggantikan nama direktori dengan ..di baris pertama. Akhirnya menggabungkan dua garis dengan pemisah.

Terima kasih kepada Hasturkun untuk 3 karakter.

jimmy23013
sumber
Terlihat menarik! Bisakah Anda menambahkan penjelasan?
Digital Trauma
1
@DigitalTrauma Ditambahkan. Tetapi pada dasarnya mereka hanya ekspresi biasa.
jimmy23013
Terima kasih! Saya akan bermain dengan ini waktu berikutnya saya berada di terminal
Digital Trauma
Anda tidak perlu menjalankan seddua kali, Anda dapat melakukannya dengan satu skrip.
Hasturkun
@Asturkun Tapi saya tidak menemukan cara untuk membuatnya bekerja N. Mungkin Anda dapat mengedit jawaban ini jika Anda tahu caranya.
jimmy23013
1

C, 119 106

void p(char*s,char* d){while(*s==*d){s++;d++;}s--;while(*s){if(*s==47||*s==92)printf("../");s++;}puts(d);}
kwokkie
sumber
p(char*s,char*d){for(;*s;)*s++-*d?*s-47||printf("../"):d++;puts(d);}68 karakter tanpa backslash
bebe
Terima kasih! Tetapi aturan 2 mengatakan keduanya harus didukung. Ada dalam output di mana saya dapat memilih satu atau yang lain (aturan 3).
kwokkie
1

Python 3, 120

a,b=(i.split('\\/'['/'in i])for i in map(input,'  '))
while[]<a[:1]==b[:1]:del a[0],b[0]
print('../'*len(a)+'/'.join(b))

Contoh:

$ python3 path.py
 /usr/share/geany/colorschemes
/usr/share/vim/vim73/ftplugin 
../../vim/vim73/ftplugin
grc
sumber
Mungkinkah ada cara yang lebih pendek untuk melakukan execoperasi baris 1 dan string?
xnor
@xnor Maybe, but I can't see it.
grc
Might map(input,' ') work for `(input(),input())? (I can't test it myself)
xnor
@xnor Yeah that works thanks!
grc
1

Ruby - 89

r=/\/|\\/
s = ARGV[0].split r
d = ARGV[1].split r
puts ("../"*(s-d).size)+((d-s).join"/")

Usage:

ruby relative.rb working/directory destination/directory
Jwosty
sumber
3
This fails for arguments like /foo/bar/foo/bar and /foo/qux/foo/bar.
Ventero
And fails for windows style paths
edc65
@edc65 The rules don't say it's necessary to support both path formats, you can do either one.
nderscore
@nderscore Rule 2 Both Windows and Unix style paths must be supported.
edc65
1
@Jwosty: Nah, itu keindahannya, bukan? Menghadirkan solusi yang sama-sama singkatand correct. I have in the past had cases where I had to revise the answer completely because of an overlooked edge case. Now, in this case I do put the blame partly on the task as well, because I believe a solid set of test cases should accompany every task, but well.
Joey
0

JavaScript - 155

function p(s,d){s=s.split(/\\|\//g);d=d.split(/\\|\//g);o=[];for(i=0;s[i]==d[i];i++);for(j=s.length-i;j--;)o[j]="..";return o.concat(d.slice(i)).join("/")}

Parses either path format but outputs with / separator.

console.log(p("/usr/share/geany/colorschemes","/usr/share/vim/vim73/ftplugin"));
../../vim/vim73/ftplugin
console.log(p("/usr/share/geany/colorschemes/test/this","/usr/share/vim/vim73/ftplugin/this/is/a/test"));
../../../../vim/vim73/ftplugin/this/is/a/test
console.log(p("c:\\windows\\system32\\drivers\\etc\\host","c:\\windows\\system\\drivers\\etc\host"));
../../../../system/drivers/etchost
Matt
sumber
0

PHP, 158 151

function r($a,$b){$a=explode('/',$a);$b=explode('/',$b);foreach($a as $k=>$v){if($v==$b[$k])$b[$k]='..';else break;}unset($b[0]);echo implode('/',$b);}

Tidak Disatukan:

function r($a,$b){
    $a=explode('/',$a);
    $b=explode('/',$b);
    foreach($a as $k=>$v){
        if($v==$b[$k])$b[$k]='..';
        else break; 
    }
    unset($b[0]);
    echo implode('/',$b);
}
// these lines are not included in count:
r('/test/test2/abc','/test/test3/abcd'); // ../test3/abcd
r('/test/test2/abc','/test/test2/abcd'); // ../../abcd
Martijn
sumber
Jawaban Anda salah. Coba buat dirs ini dan cdbentuk satu sama lain :)
core1024
0

Groovy - 144 karakter

Satu solusi:

x=args[0][1]!=':'?'/':'\\'
f={args[it].tokenize x}
s=f 0
d=f 1
n=0
while(s[n]==d[n++]);
u="..$x"*(s.size-(--n))
println "$u${d.drop(n).join x}"

contoh output:

bash$ groovy P.groovy C:\\Windows\\System32\\drivers C:\\Windows\\System32\\WindowsPowerShell\\v1.0
..\WindowsPowerShell\v1.0

bash$ groovy P.groovy /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../../vim/vim73/ftplugin

bash$ groovy P.groovy /foo/bar/foo/bar /foo/qux/foo/bar
../../../qux/foo/bar

ungolfed:

// fs = file seperator, / or \
fs = args[0][1]!=':'?'/':'\\'

s = args[0].tokenize fs
d = args[1].tokenize fs

// n = # of matching dirs from root + 1
n = 0
while (s[n] == d[n++]) ;

// up = the up-prefix. e.g. "../../..", for instance 
n--
up = "..${fs}" * (s.size-n)

println "$up${d.drop(n).join fs}"
Michael Easter
sumber