Göreli yolu yazdır


15

Açıklama

Bir kaynak yolu ve bir hedef yol verildiğinde, kaynağa göre hedefe göreli yolu çıktılayın.

kurallar

  1. Girdi stdin'den veya programa / işleve argümanlar olarak gelebilir.

  2. Hem Windows hem de Unix stil yolları desteklenmelidir.

  3. Çıktı yolu yol ayırıcı için /ve / veya kullanabilir \(seçiminiz ve her ikinizin kombinasyonu tamamdır).

  4. Göreli bir yolun mümkün olduğunu varsayabilirsiniz.

  5. Göreli yolları hesaplamak için yapılan harici programların, yerleşik veya kütüphane işlevlerinin kullanılması yasaktır (örn. Python'lar os.path.relpath)

  6. Bu

    Düzenle: Yorumlardan yeni kural.

  7. Göreli yol, mümkün olan en kısa göreli yol olmalıdır.

  8. Hedef yolun kaynak yoldan farklı olduğunu varsayın.

örnek 1

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

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

ÖRNEK 2

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

# Out
..\WindowsPowerShell\v1.0

Kural # 3 ile ilgili olarak - bir karışım uygun mu? Örn ../../vim\vim73\ftplugin.
Duncan Jones

1
En kısa göreceli yolu iade etmek zorunda mıyız yoksa herhangi bir yol vermek uygun mudur?
Howard

@Duncan Evet, bir karışım tamam.
Rynant

1
@ Bununla birlikte, en kısa göreceli yol olmalıdır.
Rynant

ilk örnek olmamalı ../vim/vim73/ftpluginmı?
Martijn

Yanıtlar:


2

CJam, 46 bayt

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

Çevrimiçi deneyin.

Örnekler

$ 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

Nasıl çalışır

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 “/”.                                                  ";

1
Bir hata var. Deneyin /aa/xile /ab/y.
jimmy23013

@ user23013: Sabit.
Dennis

2

Bash + coreutils, 116

İşte topu döndürmek için bir kabuk betiği. Daha kısa cevaplar olacağından emin olabilirsiniz:

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

Çıktı:

$ ./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
$ 

Komut dosyasının dizenin ftpluginbir dosya veya dizin olup olmadığını söylemesinin bir yolu olmadığını unutmayın . /Yukarıdaki örnekte olduğu gibi bir dizin ekleyerek açıkça bir dizin sağlayabilirsiniz .

Boşluk veya diğer komik karakterler içeren yolları işlemez. Bunun bir gereklilik olup olmadığından emin değilim. Sadece birkaç ekstra fiyat teklifi gerekecektir.


2

Javascript (E6) 104

Düzenle Çıktı için eklenen uyarı

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

Ungolfed

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

Ölçek

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


2

Yakut> = 1,9, 89 94 karakterler

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

Komut satırı bağımsız değişkenleri aracılığıyla giriş yapın. Tekrarlanan klasör adlarına sahip yollar da dahil olmak üzere hem UNIX hem de Windows stili yollar için çalışır:

$ 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

2

J - 63 karakter

Soldaki eski yolu ve sağdaki yeni yolu alan bir işlev.

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

Bu çözüm, üç parça halinde geliyor, benziyor post@loop&pre~. Patlama ile açıklanıyor:

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

/Bölünmeden önce her yola bir satır aralığı eklediğimizi , böylece Windows tarzı yolları C:bir "klasör" haline getirerek işleyeceğimizi unutmayın . Bu, Unix stili yolların başlangıcında boş bir klasörle sonuçlanır, ancak bu her zaman döngü tarafından kaldırılır.

Uygulamaya bakın:

   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

Ayrıca tryj.tk adresinden kendiniz de deneyebilirsiniz .


2

Baş, 69 66

Bunu yayınlamadım çünkü birisinin daha iyi yapabilmesi gerektiğini düşündüm. Ama görünüşe göre o kadar kolay değil.

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

Nsediki çizgiyi birbirine uydurur . İlk ifade /veya ile biten ortak önek kaldırılır \. İkinci ifade, dizin adlarını ..ilk satırdaki ile değiştirir. Son olarak, iki satırı ayırıcıyla birleştirir.

Hasturkun'a 3 karakter için teşekkürler.


İlgi çekici görünüyor! Bir açıklama ekleyebilir misiniz?
Dijital Travma

1
@DigitalTrauma Eklendi. Ama temelde bunlar sadece düzenli ifadelerdir.
jimmy23013

Teşekkürler! Bir dahaki sefere bir terminalde oynayacağım
Digital Trauma

sedİki kez çalıştırmanız gerekmez , bunu tek bir komut dosyasıyla yapabilirsiniz.
Hasturkun

@Hasturkun Ama bununla çalışmanın bir yolunu bulamadım N. Belki nasıl olduğunu biliyorsanız bu yanıtı düzenleyebilirsiniz.
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);}

p(char*s,char*d){for(;*s;)*s++-*d?*s-47||printf("../"):d++;puts(d);}68 karakter
bebe

Teşekkürler! Ancak kural 2 her ikisinin de desteklenmesi gerektiğini söylüyor. Birini veya diğerini seçebileceğim çıktıda (kural 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))

Misal:

$ python3 path.py
 /usr/share/geany/colorschemes
/usr/share/vim/vim73/ftplugin 
../../vim/vim73/ftplugin

1. satırı execve string işlemlerini yapmanın daha kısa bir yolu olabilir mi?
xnor

@xnor Belki, ama göremiyorum.
grc

Olabilir map(input,' ')iş için `(giriş (), giriş ())? (Kendim test edemiyorum)
xnor

@xnor Evet, teşekkürler!
grc

1

Yakut - 89

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

Kullanımı:

ruby relative.rb working/directory destination/directory

3
Bu, /foo/bar/foo/barve gibi argümanlar için başarısız olur /foo/qux/foo/bar.
Haziran'da Ventero

Ve Windows tarzı yollar için başarısız
edc65

@ edc65 Kurallar her iki yol biçimini desteklemenin gerekli olduğunu söylemez, ikisini de yapabilirsiniz.
nderscore

@nderscore Kural 2 Hem Windows hem de Unix stil yolları desteklenmelidir.
edc65

1
@Jwosty: Güzel olan bu, değil mi? Kısacası ikisi de bir çözüm geliyor ve doğru. Geçmişte, gözden kaçan bir uç dava nedeniyle cevabı tamamen revize etmem gereken durumlar vardı. Şimdi, bu durumda, suçu kısmen de göreve koydum, çünkü her göreve sağlam bir test örneği setinin eşlik etmesi gerektiğine inanıyorum, ama iyi.
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("/")}

Yol biçimini ayrıştırır, ancak /ayırıcıyla çıktılar .

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

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);}

Ungolfed:

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

Cevabınız doğru değil. Bu dirs yapmayı deneyin ve cdbir diğerine formu :)
core1024

0

Harika - 144 karakter

Bir çözüm:

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}"

örnek çıktı:

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}"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.