Gibt den relativen Pfad aus


15

Beschreibung

Geben Sie unter Angabe eines Quellpfads und eines Zielpfads den relativen Pfad zum Ziel in Bezug auf die Quelle aus.

Regeln

  1. Die Eingabe kann von stdin oder als Argument für das Programm / die Funktion erfolgen.

  2. Sowohl Windows- als auch Unix-Pfade müssen unterstützt werden.

  3. Der Ausgabepfad kann /und / oder \als Pfadtrennzeichen verwendet werden (Ihre Wahl und Kombination aus beiden ist in Ordnung).

  4. Sie können davon ausgehen, dass ein relativer Pfad möglich ist.

  5. Die Verwendung externer Programme, eingebauter Funktionen oder Bibliotheksfunktionen zur Berechnung relativer Pfade ist untersagt (z. B. Pythons os.path.relpath).

  6. Das ist

    Bearbeiten: Neue Regel aus Kommentaren.

  7. Der relative Pfad muss der kürzest mögliche relative Pfad sein.

  8. Angenommen, der Zielpfad unterscheidet sich vom Quellpfad.

Beispiel 1

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

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

Beispiel 2

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

# Out
..\WindowsPowerShell\v1.0

In Bezug auf Regel 3 - ist eine Mischung in Ordnung? Eg ../../vim\vim73\ftplugin.
Duncan Jones

1
Müssen wir den kürzesten relativen Pfad zurückgeben oder ist es in Ordnung, einen Pfad zu liefern?
Howard

@Duncan Ja, eine Mischung ist in Ordnung.
Rynant

1
@Howard, es muss der kürzeste relative Pfad sein.
Rynant

sollte nicht das erste Beispiel sein ../vim/vim73/ftplugin?
Martijn

Antworten:


2

CJam, 46 Bytes

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

Probieren Sie es online aus.

Beispiele

$ 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

Wie es funktioniert

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
Es hat einen Bug. Versuchen Sie es /aa/xmit /ab/y.
Jimmy23013

@ user23013: Behoben.
Dennis

2

Bash + Coreutils, 116

Hier ist ein Shell-Skript, um den Ball ins Rollen zu bringen. Ich bin mir ziemlich sicher, dass es kürzere Antworten geben wird:

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

Ausgabe:

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

Beachten Sie, dass das Skript nicht erkennen kann, ob es sich um eine Zeichenfolge handelt ftplugin eine Datei oder ein Verzeichnis ist. Sie können ein Verzeichnis explizit bereitstellen, indem Sie es /wie im obigen Beispiel mit einem anhängen .

Behandelt keine Pfade, die Leerzeichen oder andere lustige Zeichen enthalten. Ich bin mir nicht sicher, ob dies eine Anforderung ist oder nicht. Es wären nur ein paar zusätzliche Anführungszeichen erforderlich.


2

Javascript (E6) 104

Bearbeiten Hinzugefügt Warnung für die Ausgabe

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

Prüfung

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

Ruby> = 1,9, 89 94 Zeichen

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

Eingabe über Kommandozeilenargumente. Funktioniert für Pfade im UNIX- und Windows-Stil, einschließlich Pfade mit wiederholten Ordnernamen:

$ 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 Zeichen

Eine Funktion, die links den alten und rechts den neuen Pfad einnimmt.

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

Diese Lösung besteht aus drei Teilen post@loop&pre~. Erklärt durch Explosion:

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

Beachten Sie, dass wir /vor dem Aufteilen jedem Pfad einen Verweis hinzufügen , damit wir Windows-artige Pfade verarbeiten, indem wir sie C:in einen "Ordner" umwandeln. Dies führt zu einem leeren Ordner am Anfang von Pfaden im Unix-Stil, der jedoch immer von der Schleife entfernt wird.

Sehen Sie es in Aktion:

   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

Sie können es auch selbst bei tryj.tk versuchen .


2

Bash, 69 66

Ich habe diesen Beitrag nicht gepostet, weil ich dachte, jemand muss es viel besser können. Aber anscheinend ist es nicht so einfach.

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

NLässt sedzwei Zeilen zusammenpassen. Der erste Ausdruck entfernt das gemeinsame Präfix, das mit /oder endet \. Der zweite Ausdruck ersetzt die Verzeichnisnamen ..in der ersten Zeile durch. Schließlich werden die beiden Zeilen mit dem Trennzeichen verkettet.

Danke an Hasturkun für 3 Charaktere.


Sieht interessant aus! Können Sie eine Erklärung hinzufügen?
Digital Trauma

1
@DigitalTrauma Hinzugefügt. Aber im Grunde sind sie nur reguläre Ausdrücke.
Jimmy23013

Vielen Dank! Ich werde damit spielen, wenn ich das nächste Mal an einem Terminal bin
Digital Trauma

Sie müssen nicht wirklich sedzweimal ausgeführt werden, sondern können dies mit einem einzigen Skript tun.
Hasturkun

@Hasturkun Aber ich habe keinen Weg gefunden, damit es funktioniert N. Vielleicht können Sie diese Antwort bearbeiten, wenn Sie wissen, wie.
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 Zeichen ohne Backslash
Bebe

Vielen Dank! Aber Regel 2 besagt, dass beide unterstützt werden müssen. In der Ausgabe kann ich den einen oder anderen auswählen (Regel 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))

Beispiel:

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

Könnte es einen kürzeren Weg geben, um Zeile 1 mit execund String-Operationen durchzuführen?
27.

@xnor Vielleicht, aber ich kann es nicht sehen.
Grc

Könnte map(input,' ')für `(input (), input ()) funktionieren? (Ich kann es nicht selbst testen)
Xnor

@xnor Ja das funktioniert danke!
Grc

1

Rubin - 89

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

Verwendung:

ruby relative.rb working/directory destination/directory

3
Dies schlägt fehl für Argumente wie /foo/bar/foo/barund /foo/qux/foo/bar.
Ventero

Und scheitert für Windows-Stil Pfade
edc65

@ edc65 Die Regeln besagen nicht, dass beide Pfadformate unterstützt werden müssen.
Nderscore

@nderscore Regel 2 Sowohl Windows- als auch Unix-Pfade müssen unterstützt werden.
Edc65

1
@Jwosty: Nun, das ist die Schönheit, nicht wahr? Eine Lösung finden, die kurz und richtig ist. Ich hatte in der Vergangenheit Fälle, in denen ich die Antwort wegen eines übersehenen Randfalls komplett überarbeiten musste. In diesem Fall gebe ich die Schuld auch teilweise der Aufgabe, da ich glaube, dass eine solide Reihe von Testfällen jede Aufgabe begleiten sollte, aber gut.
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("/")}

Analysiert beide Pfadformate, gibt jedoch mit /Trennzeichen aus.

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

Deine Antwort ist nicht korrekt. Versuchen Sie, diese dirs und cdbilden Sie eine zu anderen :)
Core1024

0

Groovy - 144 Zeichen

Eine Lösung:

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

Beispielausgabe:

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}"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.