Kürzen Sie einen absoluten Pfad

17

Manchmal kann ein langer absoluter Pfad, z. B. in einem Befehlszeilenparameter zu einem Linux-Tool, unter Verwendung des aktuellen Arbeitsverzeichnisses als Referenz verkürzt werden:

$ pwd
/home/heh

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

$ cat mydir/myfile
my stuff

In dieser Herausforderung sollten Sie eine Funktion oder ein Programm erstellen, das zwei Parameter erhält:

  1. Absoluter Pfad im Linux-Format (beginnt mit /)
  2. Aktuelles Verzeichnis im selben Format

Die Ausgabe ist die kürzere der folgenden:

  • Eingang 1 unverändert
  • Relativer Pfad, der sich auf dieselbe Datei / dasselbe Verzeichnis bezieht wie der absolute Pfad

Feine punkte:

  • Wenn Ihr Betriebssystem mit Linux kompatibel ist, können Sie das aktuelle Verzeichnis des Systems verwenden, anstatt es als Eingabe zu empfangen
  • Sie können davon ausgehen, dass die Eingaben nur alphanumerische Zeichen (und Pfadtrennzeichen) enthalten.
  • Sie können davon ausgehen, dass der absolute Eingabepfad /am Ende kein Pfadtrennzeichen enthält
  • Sie können davon ausgehen, dass das aktuelle Eingabeverzeichnis /am Ende ein Pfadtrennzeichen hat
  • Sie können nicht davon ausgehen, dass der absolute Pfad auf eine vorhandene Datei verweist oder dass ein Teil davon ein zugängliches Verzeichnis ist. Das aktuelle Verzeichnis kann jedoch als gültig angenommen werden
  • Sie können davon ausgehen, dass es in der Nähe beider Pfade keine Symlinks gibt - da ich keine spezielle Art des Umgangs mit Symlinks benötigen möchte
  • Es ist nicht erforderlich, den Fall zu unterstützen, in dem eine der Eingaben das Stammverzeichnis ist
  • "Das aktuelle Verzeichnis" sollte ausgegeben werden als .(eine leere Zeichenkette ist ungültig)

Testfälle (Eingabe1, Eingabe2, Ausgabe):

/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
quelle
1
Msgstr "Sie können davon ausgehen, dass das aktuelle Eingabeverzeichnis /am Ende ein Pfadtrennzeichen hat ". In Ihren Beispielen ist dies jedoch nicht der Fall.
Shaggy
1
Ich mag es so, aber einige Leute mögen es anders
anatolyg
Eng verwandt .
AdmBorkBork
Was soll passieren, wenn absoluter und relativer Pfad gleich lang sind?
Dennis
1
Hier fehlen einige kritische Testfälle: /home/test /home/user/mydir/myfile /home/testund/a/b /a/b/d/e /a/b
Nathan Merrill

Antworten:

7

Julia 0,5 , 32 Bytes

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

Dies verwendet das aktuelle Arbeitsverzeichnis als Basis und kann derzeit nicht auf TIO getestet werden.

Beispiellauf

Warnung: Dies ändert Ihr Dateisystem.

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

Alternative Version, 35 Bytes (dyadisch)

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

Hierbei wird das Basisverzeichnis als Eingabe verwendet, sodass es getestet werden kann, ohne das Dateisystem zu ändern.

Probieren Sie es online!

Dennis
quelle
Die Neudefinition Base.-Fehler , sofern nicht ausdrücklich importiert, nicht wahr?
Julian Wolf
In 0.5 kann es zu Fehlern kommen, aber nur, wenn Sie diese -vor der Neudefinition verwenden. In 0.4 wird eine Warnung ausgegeben, ob Sie diese vor der Neudefinition verwenden oder nicht.
Dennis
9

JavaScript (ES6), 107 106 Bytes

Übernimmt den absoluten Pfad aund den aktuellen Pfad cin der aktuellen Syntax (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||'.'

Testfälle

Arnauld
quelle
Ein sehr schöner Trick mit [a.length]! Darf ich es ausleihen, um die Antwort von Node.j zu verbessern?
Zeppelin
@zeppelin Sicher. Tue es!
Arnauld
8

Retina , 85 83 82 Bytes

1 Byte gespart dank @MartinEnder

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

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

^$
.

Probieren Sie es online!

Kritixi Lithos
quelle
5

ES6 (Node.js REPL), 56, 54, 4645 Bytes

  • Verwenden Sie eine leere Zeichenfolge anstelle von "." um das aktuelle Verzeichnis (bei Eingabe) zu bezeichnen, -1 Byte
  • Hat den [f.length]Trick von @ Arnauld's Antwort ausgeliehen , -6 Bytes
  • Verwenden Sie das aktuelle Verzeichnis anstelle eines expliziten Verzeichnisparameters (-2 Byte)
  • Entfernte überflüssige Klammern, -2 Bytes

Golf gespielt

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

Prüfung

> 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
quelle
Erlauben wir keine node.js-Funktionen?
Downgoat
@Downgoat Javascript-Lambdas werden allgemein als Antwortform akzeptiert, daher verstehe ich nicht, warum Node.js anders gehandhabt werden sollte.
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)

Probieren Sie es online!

Ein bisschen lang, aber ich wollte eine Lösung ohne eingebaute Pfadfunktionen machen.

Bearbeiten: 9 Bytes hinzugefügt, um den von Nathan Merrill bereitgestellten Testfall zu berücksichtigen

Mathe-Junkie
quelle
3

Zsh + realpath, 58 Bytes

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

Probieren Sie es online!

Bash-Version, 62 Bytes

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

Probieren Sie es online!

Dennis
quelle
Warum nicht in zwei verschiedenen Antworten posten? Jede Sprache zählt!
Gaborsch
2

Python 3 - 53 Bytes

Verwenden von os.path:

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

Volles Programm (61 Bytes):

import os
x=input();print(min(x,os.path.relpath(x),key=len))
Matsjoyce
quelle
Oo, guter Punkt. Python ist jetzt an der Spitze, yay!
Matsjoyce
@anatolyg Ha, ich wusste, dass ich mindestens einen Testfall verpassen würde ... 😒 Jetzt ist alles behoben.
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:".";

Testfälle

Erweitert

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

Wenn ../../stattdessen eine Ausgabe of ../..zulässig ist, kann diese auf 175 Byte gekürzt werden

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

C # - 66 Bytes

Mit Hilfe eines .NET builtin und zwingt ein gültiger Pfad zu sein:

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

Wo f, tund ausgegeben werden string.

Probieren Sie es online!

aloisdg sagt Reinstate Monica
quelle