Persingkat jalur absolut

17

Terkadang jalur absolut yang panjang, misalnya parameter baris perintah ke alat linux, dapat dipersingkat, menggunakan direktori kerja saat ini sebagai referensi:

$ pwd
/home/heh

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

$ cat mydir/myfile
my stuff

Dalam tantangan ini, Anda harus membuat fungsi atau program yang menerima dua parameter:

  1. Path absolut, menggunakan format linux (dimulai dengan /)
  2. Direktori saat ini, menggunakan format yang sama

Outputnya lebih pendek dari yang berikut:

  • Masukan 1 tidak berubah
  • Path relatif yang merujuk ke file / direktori yang sama dengan path absolut

Poin bagus:

  • Jika sistem operasi Anda kompatibel dengan linux, Anda dapat menggunakan direktori sistem saat ini alih-alih menerimanya sebagai input
  • Anda dapat mengasumsikan input hanya berisi karakter alfanumerik (dan pemisah jalur)
  • Anda dapat mengasumsikan jalur absolut input tidak memiliki pemisah jalur /pada akhirnya
  • Anda dapat mengasumsikan direktori input saat ini memiliki pemisah jalur /di akhir
  • Anda tidak dapat berasumsi bahwa path absolut merujuk ke file yang ada, atau bagian mana pun dari itu adalah direktori yang dapat diakses; Namun, direktori saat ini dapat dianggap valid
  • Anda dapat berasumsi bahwa tidak ada symlink di dekat kedua jalur - karena saya tidak ingin memerlukan cara khusus untuk berurusan dengan symlink
  • Tidak perlu mendukung kasus di mana salah satu input adalah direktori root
  • "Direktori saat ini" harus berupa keluaran sebagai .(string kosong tidak valid)

Kasus uji (input1, input2, output):

/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
sumber
1
"Anda dapat mengasumsikan direktori input saat ini memiliki pemisah jalur /pada akhirnya". Namun, dalam contoh Anda, ini tidak terjadi.
Shaggy
1
Saya suka dengan cara ini, tetapi beberapa orang menyukainya dengan cara lain
anatolyg
Berhubungan erat .
AdmBorkBork
Apa yang harus terjadi jika jalur absolut dan relatif memiliki panjang yang sama?
Dennis
1
Ini kehilangan beberapa kasus uji kritis: /home/test /home/user/mydir/myfile /home/testdan/a/b /a/b/d/e /a/b
Nathan Merrill

Jawaban:

7

Julia 0,5 , 32 byte

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

Ini menggunakan direktori kerja saat ini sebagai basis dan tidak dapat diuji pada TIO saat ini.

Contoh dijalankan

Peringatan: Ini akan mengubah sistem file Anda.

$ 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 alternatif, 35 byte (diad)

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

Ini mengambil direktori dasar sebagai input, sehingga dapat diuji tanpa memodifikasi sistem file.

Cobalah online!

Dennis
sumber
Mendefinisikan ulang Base.-kesalahan kecuali diimpor secara eksplisit, bukan?
Julian Wolf
Dalam 0,5, mungkin kesalahan, tetapi hanya jika Anda menggunakan -sebelum mendefinisikannya kembali. Di 0,4, ia mencetak peringatan apakah Anda menggunakannya sebelum redefinisi atau tidak.
Dennis
9

JavaScript (ES6), 107 106 byte

Mengambil jalur absolut adan jalur saat ini cdalam sintaks currying (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||'.'

Uji kasus

Arnauld
sumber
Trik yang sangat menyenangkan [a.length]! Bolehkah saya meminjamnya untuk meningkatkan jawaban Node.js saya?
zeppelin
@zeppelin Tentu. Lakukan itu!
Arnauld
8

Retina , 85 83 82 byte

1 byte disimpan berkat @MartinEnder

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

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

^$
.

Cobalah online!

Kritixi Lithos
sumber
5

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

  • Gunakan string kosong, alih-alih "." untuk menunjukkan direktori saat ini (pada input), -1 byte
  • Meminjam [f.length]trik dari jawaban @ Arnauld , -6 byte
  • Gunakan direktori saat ini daripada parameter direktori eksplisit, -2 byte
  • Menghapus tanda kurung yang berlebihan, -2 byte

Golf

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

Uji

> 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
sumber
Apakah kita tidak mengizinkan fungsi node.js?
Downgoat
@Downgoat Javascript lambdas diterima secara luas, sebagai bentuk jawaban, jadi saya tidak melihat mengapa Node.js harus ditangani secara berbeda.
zeppelin
4

Python 2, 135 144 byte

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)

Cobalah secara Online!

Agak lama, tapi saya ingin melakukan solusi tanpa fungsi path bawaan.

Sunting: 9 byte ditambahkan ke akun untuk test case yang disediakan oleh Nathan Merrill

pecandu matematika
sumber
3

Zsh + realpath, 58 byte

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

Cobalah online!

Versi bash, 62 byte

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

Cobalah online!

Dennis
sumber
Mengapa tidak mempostingnya dalam dua jawaban yang berbeda? Setiap bahasa penting!
gaborsch
2

Python 3 - 53 byte

Menggunakan os.path:

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

Program lengkap (61 byte):

import os
x=input();print(min(x,os.path.relpath(x),key=len))
matsjoyce
sumber
Oo, poin bagus. Python memimpin sekarang, yay!
matsjoyce
@anatolyg Ha, saya tahu saya akan kehilangan setidaknya satu test case ... 😒 Semua sudah diperbaiki sekarang.
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:".";

Testcases

Diperluas

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

jika Output ../../sebagai gantinya of ../..dibolehkan dapat dipersingkat menjadi 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
sumber
0

C # - 66 byte

Menggunakan .NET builtin dan memaksa untuk menjadi jalur yang valid:

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

Di mana f, tdan output string.

Cobalah online!

aloisdg kata Reinstate Monica
sumber