Raccourcir un chemin absolu

17

Parfois, un long chemin absolu, par exemple un paramètre de ligne de commande vers un outil Linux, peut être raccourci, en utilisant le répertoire de travail actuel comme référence:

$ pwd
/home/heh

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

$ cat mydir/myfile
my stuff

Dans ce défi, vous devez créer une fonction ou un programme qui reçoit deux paramètres:

  1. Chemin absolu, en utilisant le format linux (commence par /)
  2. Répertoire courant, utilisant le même format

La sortie est la plus courte des valeurs suivantes:

  • Entrée 1 inchangée
  • Chemin relatif qui fait référence au même fichier / répertoire que le chemin absolu

Points fins:

  • Si votre système d'exploitation est compatible avec Linux, vous pouvez utiliser le répertoire actuel du système au lieu de le recevoir en entrée
  • Vous pouvez supposer que les entrées contiennent uniquement des caractères alphanumériques (et des séparateurs de chemin)
  • Vous pouvez supposer que le chemin absolu d'entrée n'a pas de séparateur de chemin /à la fin
  • Vous pouvez supposer que le répertoire courant d'entrée a un séparateur de chemin /à la fin
  • Vous ne pouvez pas supposer que le chemin absolu fait référence à un fichier existant, ou que n'importe quelle partie de celui-ci est un répertoire accessible; cependant, le répertoire courant peut être considéré comme valide
  • Vous pouvez supposer qu'il n'y a aucun lien symbolique n'importe où près de l'un ou l'autre chemin - parce que je ne veux pas avoir besoin d'une manière spéciale de traiter les liens symboliques
  • Pas besoin de prendre en charge le cas où l'une des entrées est le répertoire racine
  • "Le répertoire courant" doit être affiché en tant que .(une chaîne vide n'est pas valide)

Cas de test (entrée1, entrée2, sortie):

/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
la source
1
"Vous pouvez supposer que le répertoire courant d'entrée a un séparateur de chemin /à la fin". Cependant, dans vos exemples, ce n'est pas le cas.
Shaggy
1
J'aime ça de cette façon, mais certaines personnes l'aiment dans l'autre sens
anatolyg
Étroitement liés .
AdmBorkBork
Que doit-il se passer si les chemins absolus et relatifs ont la même longueur?
Dennis
1
Il manque certains cas de test critiques: /home/test /home/user/mydir/myfile /home/testet/a/b /a/b/d/e /a/b
Nathan Merrill

Réponses:

7

Julia 0,5 , 32 octets

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

Cela utilise le répertoire de travail actuel comme base et ne peut pas être testé sur TIO pour le moment.

Exemple d'exécution

Avertissement: cela modifiera votre système de fichiers.

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

Version alternative, 35 octets (dyadique)

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

Cela prend le répertoire de base en entrée, il peut donc être testé sans modifier le système de fichiers.

Essayez-le en ligne!

Dennis
la source
Redéfinir les Base.-erreurs sauf importation explicite, non?
Julian Wolf
En 0.5, il peut y avoir une erreur, mais seulement si vous l'utilisez -avant de le redéfinir. En 0.4, il affiche un avertissement si vous l'utilisez avant la redéfinition ou non.
Dennis
9

JavaScript (ES6), 107 106 octets

Prend le chemin absolu aet le chemin actuel cdans la syntaxe 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||'.'

Cas de test

Arnauld
la source
Une très belle astuce avec [a.length]! Puis-je l'emprunter pour améliorer ma réponse Node.js?
zeppelin
@zeppelin Bien sûr. Fonce!
Arnauld
8

Rétine , 85 83 82 octets

1 octet enregistré grâce à @MartinEnder

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

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

^$
.

Essayez-le en ligne!

Kritixi Lithos
la source
5

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

  • Utilisez une chaîne vide au lieu de "." pour désigner le répertoire courant (en entrée), -1 octet
  • A emprunté l' [f.length]astuce à la réponse de @ Arnauld , -6 octets
  • Utiliser le répertoire courant au lieu d'un paramètre de répertoire explicite, -2 octets
  • Suppression des parenthèses superflues, -2 octets

Golfé

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

Tester

> 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")
'.'
Zeppelin
la source
N'autorisons-nous pas les fonctions node.js?
Downgoat
@Downgoat Les lambdas Javascript sont largement acceptés, comme forme de réponse, donc je ne vois pas pourquoi Node.js devrait être traité différemment.
zeppelin
4

Python 2, 135 144 octets

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)

Essayez-le en ligne!

Un peu long, mais je voulais faire une solution sans fonctions de chemin d'accès intégrées.

Edit: 9 octets ajoutés pour tenir compte du cas de test fourni par Nathan Merrill

accro aux mathématiques
la source
3

Zsh + realpath, 58 octets

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

Essayez-le en ligne!

Version bash, 62 octets

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

Essayez-le en ligne!

Dennis
la source
Pourquoi ne pas l'afficher dans deux réponses différentes? Chaque langue compte!
gaborsch
2

Python 3 - 53 octets

En utilisant os.path:

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

Programme complet (61 octets):

import os
x=input();print(min(x,os.path.relpath(x),key=len))
matsjoyce
la source
Oo, bon point (s). Python est en tête maintenant, yay!
matsjoyce
@anatolyg Ha, je savais que je manquerais au moins un cas de test ... 😒 Tout est réglé maintenant.
matsjoyce
1

PHP, 204 octets

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

Cas de test

Étendu

[,$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 une sortie à la ../../place of ../..est autorisée , elle peut être raccourcissent 175 Octets

[,$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
la source
0

C # - 66 octets

Utiliser un intégré .NET et forcer à être un chemin valide:

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

f, tet la sortie sont string.

Essayez-le en ligne!

aloisdg passe à codidact.com
la source