Stampa il percorso relativo


15

Descrizione

Dato un percorso di origine e un percorso di destinazione, emette il percorso relativo alla destinazione rispetto alla sorgente.

Regole

  1. L'input può provenire da stdin o come argomenti per il programma / funzione.

  2. Devono essere supportati sia i percorsi in stile Windows che Unix.

  3. Il percorso di output può utilizzare /e / o \per il separatore di percorso (la scelta e la combinazione di entrambi è OK).

  4. Puoi presumere che sia possibile un percorso relativo.

  5. È vietato l'uso di programmi esterni, funzioni incorporate o di libreria create per il calcolo di percorsi relativi (ad es. Python os.path.relpath)

  6. Questo è

    Modifica: nuova regola dai commenti.

  7. Il percorso relativo deve essere il percorso relativo più breve possibile.

  8. Supponiamo che il percorso di destinazione sia diverso dal percorso di origine.

Esempio 1

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

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

Esempio 2

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

# Out
..\WindowsPowerShell\v1.0

Per quanto riguarda la regola n. 3: una miscela va bene? Es ../../vim\vim73\ftplugin.
Duncan Jones,

1
Dobbiamo restituire il percorso relativo più breve o va bene fornire un percorso?
Howard,

@Duncan Sì, un mix è ok.
Rynant,

1
@Howard, deve essere il percorso relativo più breve.
Rynant,

il primo esempio non dovrebbe essere ../vim/vim73/ftplugin?
Martijn,

Risposte:


2

CJam, 46 byte

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

Provalo online.

Esempi

$ 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

Come funziona

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
Ha un bug. Prova /aa/xcon /ab/y.
jimmy23013,

@ user23013: risolto.
Dennis,

2

Bash + coreutils, 116

Ecco uno script di shell per far rotolare la palla. Abbastanza sicuro che ci saranno risposte più brevi:

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

Produzione:

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

Nota che lo script non può dire se la stringa ftpluginè un file o una directory. È possibile fornire esplicitamente una directory aggiungendola con un /come nell'esempio sopra.

Non gestirà percorsi contenenti spazi bianchi o altri personaggi divertenti. Non sono sicuro se questo è un requisito o meno. Sarebbero necessarie solo alcune citazioni extra.


2

Javascript (E6) 104

Modifica Avviso aggiunto per l'output

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

Test

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

Rubino> = 1,9, 89 94 personaggi

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

Input tramite argomenti della riga di comando. Funziona con percorsi in stile UNIX e Windows, inclusi percorsi con nomi di cartelle ripetuti:

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

Una funzione che prende il vecchio percorso a sinistra e il nuovo percorso a destra.

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

Questa soluzione è composta da tre parti, che sembrano post@loop&pre~. Spiegato dall'esplosione:

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

Si noti che aggiungiamo un lead /ad ogni percorso prima della divisione, in modo da gestire i percorsi in stile Windows trasformandoli C:in una "cartella". Ciò si traduce in una cartella vuota all'inizio dei percorsi in stile Unix, ma viene sempre rimossa dal ciclo.

Guardalo in azione:

   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

Si può anche provare voi stessi a tryj.tk .


2

Bash, 69 66

Non l'ho pubblicato perché pensavo che qualcuno dovesse essere in grado di farlo molto meglio. Ma a quanto pare non è così facile.

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

Nfa sedabbinare due linee insieme. La prima espressione rimuove il prefisso comune che termina con /o \. La seconda espressione sostituisce i nomi di directory con ..nella prima riga. Infine concatena le due linee con il separatore.

Grazie a Hasturkun per 3 personaggi.


Sembra interessante! Puoi aggiungere una spiegazione?
Digital Trauma,

1
@DigitalTrauma Aggiunto. Ma fondamentalmente sono solo espressioni regolari.
jimmy23013,

Grazie! Giocherò con questa prossima volta che sarò ad un terminale
Digital Trauma il

Non è necessario eseguirlo seddue volte, è possibile farlo con un singolo script.
Hasturkun,

@Hasturkun Ma non ho trovato il modo di farlo funzionare N. Forse puoi modificare questa risposta se sai come fare.
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 caratteri senza barra rovesciata
bebe,

Grazie! Ma la regola 2 dice che entrambi devono essere supportati. È nell'output dove posso scegliere l'uno o l'altro (regola 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))

Esempio:

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

Potrebbe esserci un modo più breve per eseguire la riga 1 con exece le operazioni di stringa?
xnor

@xnor Forse, ma non riesco a vederlo.
grc,

Potrebbe map(input,' ')funzionare per `(input (), input ())? (Non posso provarlo da solo)
xnor

@xnor Sì, funziona grazie!
grc,

1

Rubino - 89

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

Uso:

ruby relative.rb working/directory destination/directory

3
Questo non riesce per argomenti come /foo/bar/foo/bare /foo/qux/foo/bar.
Ventero,

E non riesce per i percorsi in stile Windows
edc65,

@ edc65 Le regole non dicono che è necessario supportare entrambi i formati di percorso, puoi fare uno dei due.
nderscore,

@nderscore Regola 2 Devono essere supportati sia i percorsi in stile Windows che Unix.
edc65,

1
@Jwosty: Beh, questa è la bellezza, vero? Trovando una soluzione che sia breve e corretta. In passato ho avuto casi in cui ho dovuto rivedere completamente la risposta a causa di un caso marginale trascurato. Ora, in questo caso, metto anche la colpa in parte sul compito, perché credo che un solido set di casi di test dovrebbe accompagnare ogni compito, ma bene.
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("/")}

Analizza il formato del percorso ma emette con il /separatore.

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

La tua risposta non è corretta Prova a creare queste directory e cdformale l'una con l'altra :)
core1024

0

Groovy - 144 caratteri

Una soluzione:

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

esempio di 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}"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.