Розрахунок у каталозі


19

Для цього завдання вам буде наданий абсолютний шлях та "новий" шлях (який може бути абсолютним або відносним), і вам потрібно повернути остаточний шлях.

Наприклад, якщо ваш поточний каталог був /var/tmp/test:

my_dirабо my_dir/ повинні повернутися/var/tmp/test/my_dir

../../my_dir повинен повернутися /var/my_dir

/my_dir/./ повинен повернутися /my_dir

../../../../../ повинен повернутися /

Щоб бути більш педантичним:

  • Каталог є непорожній рядок , що складається з буквено - цифрових символів і символів -, _або.
  • Шлях - це список 0 або більше каталогів , розділених за допомогою /. Абсолютний шлях починається з а /, відносний шлях - ні. Шляхи можуть включати закінчення /.

Вам потрібно "розв'язати" другий шлях, задавши перший шлях.

Процес вирішення:

  1. Перевірте, чи другий шлях відносний. Якщо так, то вставте каталоги абсолютного шляху до початку другого шляху.
  2. Якщо будь-який із каталогів є .., видаліть його та попередній каталог. Якщо це перший каталог, то просто видаліть його.
  3. Якщо будь-який із каталогів є ., видаліть його.
  4. Виведіть кінцевий абсолютний шлях. Не слід виводити закінчення /.

Вам не потрібно обробляти неправильний ввід. Команди повинні працювати, незалежно від того, чи справді передані каталоги існують на вашій машині. Можна припустити, що все - це каталог, навіть якщо він має розширення.

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

Absolute      New          Output
"/a/b/c"      "d"       -> "/a/b/c/d" 
"/a/b/c/"     "d"       -> "/a/b/c/d"
"/a/b/c/"     "d/"      -> "/a/b/c/d"
"/a/b/c"      "/d"      -> "/d"
"/a/b/c"      "/d/"     -> "/d"
"/../a/b/c/"  "d"       -> "/a/b/c/d"
"/a/../b/c/"  "d"       -> "/b/c/d"
"/a/b/../c"   "d"       -> "/a/c/d"
"/a/b/c/.."   "d"       -> "/a/b/d"
"/a/b/c/"     ".."      -> "/a/b"
"/a/b/c"      "../d"    -> "/a/b/d"
"/a/b/c"      "/../d"   -> "/d"
"/a/b/c"      ""        -> "/a/b/c"
"/a/b/c"      "."       -> "/a/b/c"
"/a/b/c"      "./d"     -> "/a/b/c/d"
"/a/b/c"      "/./d"    -> "/d"
"/a/b/c"      "d.txt"   -> "/a/b/c/d.txt"
"/a/b/c"      "d."      -> "/a/b/c/d."
"/a/b/c"      ".txt"    -> "/a/b/c/.txt"
"/a/b/c"      ".txt/d"  -> "/a/b/c/.txt/d"
"/a/b/."      "./././." -> "/a/b"
"/direc"      "tory"    -> "/direc/tory"
"/a-_.b/"     "__._-."  -> "/a-_.b/__._-."
"/a/b"        "../.."   -> "/"
"/a/b"        "../../.."-> "/"
"/a"          "../../.."-> "/"
"/"           ""        -> "/"
"/"           "a"       -> "/a"
"/.."         "a"       -> "/a"
"/."          ""        -> "/"

Це , тому робіть подання якомога коротшим на своїй улюбленій мові!


Здається, що деякі відповіді припускають, що файли (або символьні посилання) з тим самим іменем, що і будь-яка частина дерева каталогів) не існують на апараті. Це дозволено?
Денніс

Чи можемо ми взяти два входи в будь-якому бажаному порядку?
Пуховик

Дурне питання ... чи можу я мати побічні ефекти? Зокрема, такі побічні ефекти, як, гм, mkdir $patha; cd $patha; mkdir $pathb; cd $pathb; echo `abspath`(чи щось)?
кіт

@dennis. Вихід програм повинен бути незалежним від файлової системи
Nathan Merrill

@downgoat це добре
Натан Меррілл

Відповіді:



3

Пітон, 53 байти

from os.path import*;p=lambda a,n:normpath(join(a,n))

3

Пакетна, 282 281 279 276 байт

@echo off
set a=\
set r=%~2
if "%r%"=="" set r=%~1
if not %r:~,1%==/ set r=%~1/%~2
for %%a in (%r:/= %)do call:x %%a
if not %a%==\ set a=%a:~,-1%
echo %a:\=/%
exit/b
:x
if %1==. exit/b
if not %1==.. set a=%a%%1\&exit/b
if not %a%==\ for %%a in (%a:~,-1%)do set a=%%~pa

Роздратовано Пакетні вирази зазвичай не люблять порожні змінні. Редагувати: Збережено 1 байт завдяки @ CᴏɴᴏʀO'Bʀɪᴇɴ та 2 байти завдяки @ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ (і купа байтів також за іншими відповідями, хоча, на жаль, не зафіксовано).


Я думаю, ви можете видалити пробіл між callі: x`, ні?
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Так, ви можете. У мене є маса відповідей, які потребують оновлення в цьому випадку ...
Ніл

2

Python 2, 265 260 254 байт

y=lambda:[x for x in raw_input().split("/")if x!=""and x!="."]
a=y();n=y();m=len(a)-1
while m>0:
 if a[m]==".."and m>0:del a[m];del a[m-1];m-=1
 elif a[m]=="..":del a[m]
 m-=1
for i in n:
 if i==".."and len(a)>0:del a[-1]
 else:a+=i,
print"/"+"/".join(a)

1

Пітон, 142 137 байт

def p(a,n,r=[],S="/"):
 for s in[s for s in((n[:1]!=S)*a+S+n).split(S)if"."!=s and s]:e=s!="..";r=[s]*e+r[1-e:]
 return S+S.join(r[::-1])

1

Баш, 41 байт

Цей сценарій bash має побічний ефект від створення каталогів, якщо вони не існують, але він повинен відповідати вимогам. Дякую Карлу та Нілу за вдосконалення.

mkdir -p $1;cd $1;mkdir -p $2;cd "$2";pwd

Використання: bash getpath.sh "абсолютний" "новий"

Якщо вам не подобається stderr, коли другий аргумент є порожнім рядком, ви можете перевірити його наступним чином (48 байт):

mkdir -p $1;cd $1;[ $2 ]&&mkdir -p $2&&cd $2;pwd

Попередня спроба 30 байт (вимагає існування каталогів): cd $ 1; [$ 2] && cd $ 2; echopwd


Питання говорить, що команди повинні працювати, незалежно від того, чи існують передані каталоги на вашій машині.
Денніс

А, бачу. Дуже погано.
Брін

Привіт, і ласкаво просимо до PPCG! Як правило, якщо ваша відповідь не працює, ви її видаляєте. Ви можете натиснути посилання для видалення над цим коментарем.
NoOneIsHere

Ви могли mkdir -pпереконатися, що вони існують.
Карл Напф

Дякую, я пробую версію з mkdir. Я видалю цю відповідь і додаю нову, якщо розберусь.
Брін

1

C #, 43 байти

(x,y)=>Path.GetFullPath(Path.Combine(x,y));

Збережено 1 байт завдяки @aloisdg

Path.Combineз'єднує аргументи і Path.GetFullPathвирішує ..\s


Привіт, і ласкаво просимо до PPCG! Це не дійсна програма - або включайте mainі клас, або змінюйте його на lanbda: a,b->...
NoOneIsHere

Я збирався розмістити це :) Приємне перше подання! ви можете видалити пробіл після ,: (x, y)=>(x,y)
aloisdg каже: Поновити Моніку


1

Вузол REPL, 8 12 байт

path.resolve

На щастя, вам не доведеться require()стандартні модулі в REPL.

Тестовий сюїт

https://repl.it/Cclo/1

(Якщо результат у кінці є true, він збігається)


1

Javascript, 210 байт

function p(a,b){d='.';e=d+d;s='/';t='split';u='splice';r=(b[0]===s?[]:a[t](s)).concat(b[t](s));for(i=0;i<r.length;r[i]===e&&r[u](i?i-1:i,i?2:1)?(i&&i--):i++)(!r[i]||r[i]===d)&&r[u](i,1)&&i--;return s+r.join(s)}

Ось тестовий набір

З розривами рядків замість крапки з комою:

function p(a,b) {
    d='.'
    e=d+d
    s='/'
    t='split'
    u='splice'

    r=(b[0]===s?[]:a[t](s)).concat(b[t](s))

    for(i=0;i<r.length;r[i]===e&&r[u](i?i-1:i,i?2:1)?(i&&i--):i++)
        (!r[i]||r[i]===d)&&r[u](i,1)&&i--

    return s+r.join(s)
}

0

Java 7, 83 байти

String p(String a,String b){return Paths.get(a).resolve(b).normalize().toString();}

normalizeпотрібен для розгляду відносних посилань. addвикористовується для обробки другого шляху, починаючи з /якого Paths.get(a, b)не обробляється, як зазначено.


Привіт, і ласкаво просимо до PPCG! Це хороший перший пост!
NoOneIsHere

0

Баш, 38 байт

[[ $2 = /* ]]||p=$1
realpath -sm $p/$2

Не вимагає кореневих привілеїв і не робить припущень щодо існуючих або неіснуючих файлів, каталогів або символічних посилань.

Перевірте це на Ideone .

Як це працює

[[ $2 = /* ]]тестує, чи починається другий аргумент командного рядка /.

Якщо це не так, шлях є відносним і p=$1встановлює змінну p на перший аргумент командного рядка.

Цей шлях $p/$2є, /$2якщо $2це абсолютний шлях, і $1/$2якщо він є реальним.

Нарешті, realpath -sm $p/$2друкується абсолютний канонічний шлях Росії $p/$2. У -sкомутаторі марка Realpath ігнорує символічні посилання, а також -mперемикач відсутній компоненти.


0

Рубін, 16 байт

Оскільки, мабуть, використання методу зі стандартної бібліотеки дозволено:

File.expand_path

Дивіться набір тестів на repl.it .


Введення через змінні заборонено, але подання функції є, а це означає, що слід скоротити її до File.expand_path:)
Nathan Merrill

Я також рекомендую фактично перевірити його набір тестів, щоб переконатися, що він працює правильно у всіх тестових випадках.
Натан Меррілл

@NathanMerrill Я це зробив, але я продовжую щось наклеювати на repl.it.
Йордан

Відредаговано, щоб включити посилання тестового набору.
Йордан

0

GNU sed , 81 59 + 1 = 60 байт

+1 байт для -rпрапора. Очікує, що вхід на STDIN розділяється одним пробілом.

s:.+ /::
s:/? :/:
:
s:/$|[^/]+/+\.\.|\.(/|$):\1:
t
s:^/*:/:

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

Пояснення

s:.+ /::  # If the second argument starts with a slash, drop the first argument
s:/? :/:  # Join the first and second arguments with a slash, dropping duplicate slashes
:
  s:/$|[^/]+/+\.\.|\.(/|$):\1:  # Drop trailing slashes, resolve double and single dots
  t                             # If the above substitution was made, branch to :
s:^/*:/:  # Ensure output begins with a single slash

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