Сократить абсолютный путь

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
.
anatolyg
источник
1
Msgstr "Вы можете предположить, что входной текущий каталог имеет разделитель пути /в конце". Однако в ваших примерах это не так.
Лохматый
1
Мне нравится это так, но некоторым людям нравится это по-другому
Анатолий
Что должно произойти, если абсолютный и относительный путь имеют одинаковую длину?
Деннис
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в синтаксисе карри (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||'.'

Контрольные примеры

Arnauld
источник
Очень хороший трюк с [a.length]! Могу ли я взять его, чтобы улучшить свой ответ на Node.js?
Цеппелин
@zeppelin Конечно. Действуй!
Арно
5

ES6 (Node.js REPL), 56, 54, 4645 байтов

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

Golfed

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
@Downgoat Jamascript lambdas широко используются как форма ответа, поэтому я не понимаю, почему 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 байтов добавлены к учетной записи для теста, предоставленного Натаном Меррилл

математик наркоман
источник
3

Zsh + realpath, 58 байт

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

Попробуйте онлайн!

Bash версия, 62 байта

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

Попробуйте онлайн!

Деннис
источник
Почему бы не опубликовать его в двух разных ответах? Каждый язык имеет значение!
gaborsch
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))
matsjoyce
источник
О, хорошие моменты. Питон впереди, да!
matsjoyce
@anatolyg Ха, я знал, что пропущу хотя бы один тестовый пример ... fixed Все исправлено.
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:".";

Testcases

расширенный

[,$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:".";
Йорг Хюльсерманн
источник