Acortar un camino absoluto

17

A veces, se puede acortar una ruta absoluta larga, por ejemplo, un parámetro de línea de comando a una herramienta de Linux, utilizando el directorio de trabajo actual como referencia:

$ pwd
/home/heh

$ cat /home/heh/mydir/myfile
my stuff

$ cat mydir/myfile
my stuff

En este desafío, debe hacer una función o un programa que reciba dos parámetros:

  1. Ruta absoluta, utilizando el formato de Linux (comienza con /)
  2. Directorio actual, usando el mismo formato

La salida es la más corta de las siguientes:

  • Entrada 1 sin cambios
  • Ruta relativa que se refiere al mismo archivo / directorio que la ruta absoluta

Puntos finos:

  • Si su sistema operativo es compatible con Linux, puede usar el directorio actual del sistema en lugar de recibirlo como entrada
  • Puede suponer que las entradas contienen solo caracteres alfanuméricos (y separadores de ruta)
  • Puede suponer que la ruta absoluta de entrada no tiene un separador de ruta /al final
  • Puede suponer que el directorio actual de entrada tiene un separador de ruta /al final
  • No puede suponer que la ruta absoluta se refiere a un archivo existente, o que cualquier parte de este es un directorio accesible; sin embargo, el directorio actual se puede suponer válido
  • Puede suponer que no hay enlaces simbólicos en ninguna parte cerca de ninguna ruta, porque no quiero requerir ninguna forma especial de tratar con enlaces simbólicos
  • No es necesario admitir el caso donde cualquiera de las entradas es el directorio raíz
  • "El directorio actual" debe aparecer como .(una cadena vacía no es válida)

Casos de prueba (entrada1, entrada2, salida):

/home/user/mydir/myfile
/home/user
mydir/myfile

/var/users/admin/secret/passwd
/var/users/joe/hack
../../admin/secret/passwd

/home/user/myfile
/tmp/someplace
/home/user/myfile

/dir1/dir2
/dir1/dir2/dir3/dir4
../..

/dir1/dir2
/dir1/dir2
.
anatolyg
fuente
1
"Puede suponer que el directorio actual de entrada tiene un separador de ruta /al final". Sin embargo, en sus ejemplos, este no es el caso.
Shaggy
1
Me gusta de esta manera, pero a algunas personas les gusta de otra manera
anatolyg
¿Qué debería pasar si la ruta absoluta y relativa tienen la misma longitud?
Dennis
1
Faltan algunos casos de prueba críticos: /home/test /home/user/mydir/myfile /home/testy/a/b /a/b/d/e /a/b
Nathan Merrill

Respuestas:

7

Julia 0.5 , 32 bytes

!,~=relpath,endof
t->~t<~!t?t:!t

Esto utiliza el directorio de trabajo actual como base y no se puede probar en TIO en este momento.

Ejecución de ejemplo

Advertencia: Esto alterará su sistema de archivos.

$ sudo julia --quiet
julia> function test(target,base)
       mkpath(base)
       cd(base)
       shorten(target)
       end
test (generic function with 1 method)
julia> !,~=relpath,endof
(relpath,endof)

julia> shorten = t->~t<~!t?t:!t
(::#1) (generic function with 1 method)

julia> test("/home/user/mydir/myfile","/home/user")
"mydir/myfile"

julia> test("/var/users/admin/secret/passwd","/var/users/joe/hack")
"../../admin/secret/passwd"

julia> test("/home/user/myfile","/tmp/someplace")
"/home/user/myfile"

julia> test("/dir1/dir2","/dir1/dir2/dir3/dir4")
"../.."

julia> test("/dir1/dir2","/dir1/dir2")
"."

Versión alternativa, 35 bytes (diádica)

^,~=relpath,endof
t-b=~t<~t^b?t:t^b

Esto toma el directorio base como entrada, por lo que puede probarse sin modificar el sistema de archivos.

Pruébalo en línea!

Dennis
fuente
Redefinir Base.-errores a menos que se importe explícitamente, ¿no?
Julian Wolf
En 0.5, puede producirse un error, pero solo si lo usa -antes de redefinirlo. En 0.4, imprime una advertencia si lo usa antes de la redefinición o no.
Dennis
9

JavaScript (ES6), 107 106 bytes

Toma la ruta absoluta ay la ruta actual cen la sintaxis de curry (a)(c).

a=>c=>(A=a.split`/`,s='',c.split`/`.map(d=>!s&A[0]==d?A.shift():s+='../'),s+=A.join`/`)[a.length]?a:s||'.'

Casos de prueba

Arnauld
fuente
Un muy buen truco con [a.length]! ¿Puedo pedirlo prestado para mejorar mi respuesta de Node.js?
zeppelin
@zeppelin Claro. ¡Ve a por ello!
Arnauld
8

Retina , 85 83 82 bytes

1 byte guardado gracias a @MartinEnder

^(..+)(.*;)\1
%$2
(%?)(.*);(.*)
$1$3;$2
\w+(?=.*;)
..
%;/

;
/
.*//
/
%/?|/$

^$
.

Pruébalo en línea!

Kritixi Lithos
fuente
5

ES6 (Node.js REPL), 56, 54, 46, 45 bytes

  • Use una cadena vacía, en lugar de "." para denotar el directorio actual (en la entrada), -1 byte
  • Tomó prestado el [f.length]truco de la respuesta de @ Arnauld , -6 bytes
  • Use el directorio actual en lugar de un parámetro de directorio explícito, -2 bytes
  • Se eliminaron paréntesis superfluos, -2 bytes

Golfed

f=>(r=path.relative("",f))[f.length]?f:r||"."

Prueba

> F=f=>(r=path.relative("",f))[f.length]?f:r||"."
[Function: F]

> F("/home/user/mydir/myfile")
'mydir/myfile'

> F("/var/users/admin/secret/passwd")
'../../admin/secret/passwd'

> F("/home/user/myfile")
'/home/user/myfile'

> F("/dir1/dir2")
'../..'

> F("/dir1/dir2")
'.'
zepelín
fuente
¿No permitimos las funciones de node.js?
Downgoat
@Downgoat Javascript lambdas son ampliamente aceptados, como una forma de respuesta, por lo que no veo por qué Node.js debe manejarse de manera diferente.
zepelín
4

Python 2, 135 144 bytes

i=0
a,c=input()
b,d=a.split('/')*(a!=c),c.split('/')
while b[:i+1]==d[:i+1]:i+=1
print'.'[i:]or min('/'.join(['..']*len(d[i:])+b[i:]),a,key=len)

Pruébalo en línea!

Algo largo, pero quería hacer una solución sin funciones de ruta incorporadas.

Editar: 9 bytes agregados a la cuenta para el caso de prueba proporcionado por Nathan Merrill

adicto a las matemáticas
fuente
3

Zsh + realpath, 58 bytes

r=`realpath -m --relative-to=$*`
(($#2<$#r))&&r=$2
echo $r

Pruébalo en línea!

Versión bash, 62 bytes

r=`realpath -m --relative-to=$*`
((${#2}<${#r}))&&r=$2
echo $r

Pruébalo en línea!

Dennis
fuente
¿Por qué no publicarlo en dos respuestas diferentes? ¡Cada idioma importa!
gaborsch
2

Python 3 - 53 bytes

Utilizando os.path:

import os
lambda x:min(x,os.path.relpath(x),key=len)

Programa completo (61 bytes):

import os
x=input();print(min(x,os.path.relpath(x),key=len))
matsjoyce
fuente
Oo, buen punto (s). Python está a la cabeza ahora, ¡yay!
matsjoyce
@anatolyg Ja, sabía que me perdería al menos un caso de prueba ... 😒 Todo solucionado ahora.
matsjoyce
1

PHP, 204 bytes

[,$l,$p]=$argv;$z=($d=array_diff_assoc)($y=($w=explode)("/",$p),$x=$w("/",$l));$m=str_pad("",3*count($z)-1,"../");$j=join("/",$r=$d($x,$y));echo$l!=$p?strlen($u=$m&&$j?"$m/$j":$m.$j)<strlen($l)?$u:$l:".";

Casos de prueba

Expandido

[,$l,$p]=$argv;
$z=($d=array_diff_assoc)($y=($w=explode)("/",$p),$x=$w("/",$l));
$m=str_pad("",3*count($z)-1,"../");
$j=join("/",$r=$d($x,$y));
echo$l!=$p
    ?strlen($u=$m&&$j?"$m/$j":$m.$j)<strlen($l)
      ?$u
      :$l
    :".";

Si una salida ../../en lugar of ../..se deja que se puede acortar a 175 Bytes

[,$l,$p]=$argv;$z=($d=array_diff_assoc)($y=($w=explode)("/",$p),$x=$w("/",$l));echo$l!=$p?strlen($m=str_pad("",3*count($z),"../").join("/",$r=$d($x,$y)))<strlen($l)?$m:$l:".";
Jörg Hülsermann
fuente
0

C # - 66 bytes

Usando un .NET incorporado y forzando a ser una ruta válida:

(f,t)=>f==t?".":new Uri("/"+t).MakeRelativeUri(new Uri("/"+f))+"";

Donde f, ty la salida son string.

Pruébalo en línea!

aloisdg dice Reinstate Monica
fuente