Encurte um caminho absoluto

17

Às vezes, um longo caminho absoluto, por exemplo, um parâmetro de linha de comando para uma ferramenta Linux, pode ser reduzido, usando o diretório de trabalho atual como referência:

$ pwd
/home/heh

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

$ cat mydir/myfile
my stuff

Neste desafio, você deve criar uma função ou um programa que receba dois parâmetros:

  1. Caminho absoluto, usando o formato linux (começa com /)
  2. Diretório atual, usando o mesmo formato

A saída é a mais curta do seguinte:

  • Entrada 1 inalterada
  • Caminho relativo que se refere ao mesmo arquivo / diretório que o caminho absoluto

Pontos finos:

  • Se o seu sistema operacional for compatível com linux, você poderá usar o diretório atual do sistema em vez de recebê-lo como entrada
  • Você pode assumir que as entradas contêm apenas caracteres alfanuméricos (e separadores de caminho)
  • Você pode assumir que o caminho absoluto de entrada não possui um separador de caminho /no final
  • Você pode assumir que o diretório atual de entrada possui um separador de caminho /no final
  • Você não pode assumir que o caminho absoluto se refere a um arquivo existente ou que qualquer parte dele seja um diretório acessível; no entanto, o diretório atual pode ser considerado válido
  • Você pode assumir que não há links simbólicos em nenhum lugar próximo a nenhum dos caminhos - porque eu não quero exigir nenhuma maneira especial de lidar com links simbólicos
  • Não há necessidade de suportar o caso em que uma das entradas é o diretório raiz
  • "O diretório atual" deve ser exibido como .(uma sequência vazia não é válida)

Casos de teste (entrada1, entrada2, saída):

/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
fonte
11
"Você pode assumir que o diretório atual de entrada possui um separador de caminho /no final". No entanto, em seus exemplos, esse não é o caso.
Shaggy
11
Eu gosto desse jeito, mas algumas pessoas como a outra maneira
anatolyg
Intimamente relacionado .
AdmBorkBork
O que deve acontecer se o caminho absoluto e relativo tiver o mesmo comprimento?
Dennis
11
Isso está faltando alguns casos de teste críticos: /home/test /home/user/mydir/myfile /home/teste/a/b /a/b/d/e /a/b
Nathan Merrill

Respostas:

7

Julia 0,5 , 32 bytes

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

Isso usa o diretório de trabalho atual como base e não pode ser testado no TIO no momento.

Exemplo de execução

Aviso: Isso irá alterar seu sistema de arquivos.

$ 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")
"."

Versão alternativa, 35 bytes (diádica)

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

Isso leva o diretório base como entrada, para que possa ser testado sem modificar o sistema de arquivos.

Experimente online!

Dennis
fonte
Redefinindo Base.-erros, a menos que seja explicitamente importado, não?
Julian Lobo
Em 0.5, pode haver erro, mas somente se você o usar -antes de redefini-lo. No 0.4, ele imprime um aviso se você o usa antes da redefinição ou não.
Dennis19 /
9

JavaScript (ES6), 107 106 bytes

Pega o caminho absoluto ae o caminho atual cna sintaxe 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 teste

Arnauld
fonte
Um truque muito bom com [a.length]! Posso emprestá-lo para melhorar minha resposta do Node.js.?
Zeppelin
@zeppelin Claro. Vá em frente!
Arnauld
8

Retina , 85 83 82 bytes

1 byte salvo graças a @MartinEnder

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

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

^$
.

Experimente online!

Kritixi Lithos
fonte
5

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

  • Use string vazia, em vez de "." para indicar o diretório atual (na entrada), -1 byte
  • Emprestado o [f.length]truque da resposta de @ Arnauld , -6 bytes
  • Use o diretório atual em vez de um parâmetro de diretório explícito, -2 bytes
  • Parênteses supérfluos removidos, -2 bytes

Golfe

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

Teste

> 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")
'.'
zepelim
fonte
Não permitimos funções node.js.?
Downgoat
As lambdas Javascript do @Downgoat são amplamente aceitas, como uma forma de resposta, por isso não vejo por que o Node.js deve ser tratado de maneira diferente.
Zeppelin
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)

Experimente Online!

Meio que demorou, mas eu queria fazer uma solução sem as funções de caminho internas.

Edit: 9 bytes adicionados à conta do caso de teste fornecido por Nathan Merrill

viciado em matemática
fonte
3

Zsh + caminho real, 58 bytes

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

Experimente online!

Versão Bash, 62 bytes

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

Experimente online!

Dennis
fonte
Por que não publicá-lo em duas respostas diferentes? Toda língua importa!
precisa saber é o seguinte
2

Python 3 - 53 bytes

Usando 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
fonte
Oo, bons pontos. Python está na liderança agora, yay!
matsjoyce
@anatolyg Ha, eu sabia que sentiria falta de pelo menos um caso de teste ... 😒 Tudo corrigido agora.
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 teste

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
    :".";

Se uma saída ../../em vez of ../..é permitido pode ser encurtar 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
fonte
0

C # - 66 bytes

Usando um .NET embutido e forçando um caminho válido:

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

Onde f, te de saída sãostring .

Experimente online!

aloisdg diz Restabelecer Monica
fonte