Скоротіть абсолютний шлях


17

Іноді довгий абсолютний шлях, наприклад, параметр командного рядка до інструмента Linux, може бути скорочений, використовуючи поточну робочу директорію в якості посилання:

$ pwd
/home/heh

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

$ cat mydir/myfile
my stuff

У цьому виклику слід створити функцію або програму, яка отримує два параметри:

  1. Абсолютний шлях, використовуючи формат linux (починається з /)
  2. Поточний каталог, використовуючи той самий формат

Вихід коротший з наступного:

  • Введення 1 без змін
  • Відносний шлях, який посилається на той самий файл / каталог, як і абсолютний шлях

Тонкі бали:

  • Якщо ваша операційна система сумісна з linux, ви можете використовувати поточний каталог системи замість того, щоб отримувати її як вхід
  • Можна припустити, що входи містять лише буквено-цифрові символи (та роздільники шляхів)
  • Можна припустити, що абсолютний шлях введення не має в /кінці розділювача
  • Можна припустити, що в каталозі поточного входу є роздільник шляху /в кінці
  • Ви не можете припустити, що абсолютний шлях відноситься до наявного файлу або що будь-яка його частина є доступним каталогом; однак, поточний каталог можна вважати дійсним
  • Ви можете припустити, що поблизу обох контурів немає жодних посилань - тому що я не хочу вимагати особливих способів поводження з символьними посиланнями
  • Не потрібно підтримувати випадок, коли будь-який із входів є кореневою каталогом
  • "Поточний каталог" повинен виводитися як .(порожній рядок недійсний)

Тестові приклади (вхід1, вхід2, вихід):

/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
.

1
"Ви можете припустити, що в каталозі поточного входу є роздільник шляху /в кінці". Однак у ваших прикладах це не так.
Кудлатий

1
Мені це подобається таким чином, але деяким людям подобається інше
anatolyg


Що має відбутися, якщо абсолютний та відносний шлях мають однакову довжину?
Денніс

1
Тут не вистачає деяких критичних тестових випадків: /home/test /home/user/mydir/myfile /home/testі/a/b /a/b/d/e /a/b
Натан Меррілл

Відповіді:


7

Джулія 0,5 , 32 байти

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

При цьому використовується поточний робочий каталог як базовий, і наразі його не можна перевірити на TIO.

Приклад виконання

Попередження: Це змінить вашу файлову систему.

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

Альтернативна версія, 35 байт (діадічний)

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

Це приймає базовий каталог як вхідний, тому його можна перевірити без зміни файлової системи.

Спробуйте в Інтернеті!


Перевизначення Base.-помилок, якщо явно не імпортовано, ні?
Джуліан Вольф

У 0,5 він може помилитися, але лише у тому випадку, якщо ви використовуєте його, -перш ніж визначати його. В 0.4 він друкує попередження, використовуєте ви його до перегляду чи ні.
Денніс

9

JavaScript (ES6), 107 106 байт

Бере абсолютний шлях aта поточний шлях cу синтаксисі 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||'.'

Тестові справи


Дуже приємний трюк з [a.length]! Чи можу я позичити його для вдосконалення відповіді на Node.js?
zeppelin

@zeppelin Звичайно. Дій!
Арнольд


5

ES6 (Node.js REPL), 56, 54, 46, 45 байт

  • Використовуйте порожній рядок замість "." для позначення поточного каталогу (на вході) -1 байт
  • Запозичив [f.length]трюк з @ Arnauld в відповідь , -6 байт
  • Використовуйте поточний каталог замість явного параметра каталогу, -2 байти
  • Видалено зайві дужки, -2 байти

Гольф

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

Тест

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

Чи не дозволено функції node.js?
Пуховик

@Downgoat Лямбди Javascript широко сприймаються як форма відповіді, тому я не розумію, чому з Node.js слід по-різному оброблятись.
зеппелін

4

Python 2, 135 144 байт

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)

Спробуйте в Інтернеті!

Вигляд довгий, але я хотів зробити рішення без вбудованих функцій шляху.

Редагувати: 9 байт додано в обліковий запис для тестового випадку, наданого Натаном Мерріллом



2

Python 3 - 53 байти

Використання os.path:

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

Повна програма (61 байт):

import os
x=input();print(min(x,os.path.relpath(x),key=len))

О, хороший бал (и). Зараз Python лідирує, так!
matsjoyce

@anatolyg Ха, я знав, що пропущу принаймні один тестовий випадок ... 😒 Все виправлено зараз.
matsjoyce

1

PHP, 204 байт

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

Тестові шафи

Розширено

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

якщо ../../замість цього of ../..дозволено вихід , його можна скоротити до 175 байт

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.