Cálculo de diretório


19

Para esse desafio, você receberá um caminho absoluto e um "novo" (que pode ser absoluto ou relativo) e precisará retornar o caminho final.

Por exemplo, se seu diretório atual fosse /var/tmp/test:

my_dirou my_dir/ deveria retornar/var/tmp/test/my_dir

../../my_dir deve retornar /var/my_dir

/my_dir/./ deve retornar /my_dir

../../../../../ deve retornar /

Para ser mais pedante:

  • Um diretório é uma string não-vazia que consiste de caracteres alfanuméricos e os símbolos -, _ou.
  • Um caminho é uma lista de 0 ou mais diretórios , separados usando /. Um caminho absoluto começa com a /, um caminho relativo não. Os caminhos podem incluir um final /.

Você precisa "resolver" o segundo caminho, dado o primeiro caminho.

O processo de resolução é:

  1. Teste se o segundo caminho é relativo. Nesse caso, insira os diretórios do caminho absoluto no início do segundo caminho.
  2. Se algum dos diretórios for .., remova-o e o diretório anterior. Se for o primeiro diretório, basta removê-lo.
  3. Se algum dos diretórios estiver ., remova-o.
  4. Saída o caminho absoluto final. Você não deve produzir um final /.

Você não precisa lidar com entradas incorretas. Os comandos devem funcionar, independentemente de os diretórios transmitidos existirem na sua máquina. Você pode assumir que tudo é um diretório, mesmo que tenha uma extensão.

Casos de teste

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

Este é um , então faça seus envios o mais curto possível no seu idioma favorito!


Algumas respostas parecem assumir que arquivos (ou links simbólicos) com o mesmo nome que qualquer parte da árvore de diretórios) não existem na máquina. Isso é permitido?
Dennis

Podemos pegar as duas entradas na ordem que desejarmos?
Downgoat

Pergunta estúpida ... posso ter efeitos colaterais? Especificamente, efeitos colaterais como, hum, mkdir $patha; cd $patha; mkdir $pathb; cd $pathb; echo `abspath`(ou algo assim)?
gato

@dennis. A saída dos programas deve ser independente do sistema de arquivos
Nathan Merrill

@downgoat está bom #
Nathan Merrill

Respostas:


7

Retina , 44 bytes

+`.+ /| |/\.?/
/
+1`/?[^/]*/\.\.|/\.?$

^$
/

A entrada deve ser os dois caminhos separados por um único espaço.

Experimente online! (A primeira linha ativa um conjunto de testes separado por avanço de linha.)


3

Python, 53 bytes

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

3

Lote, 282 281 279 276 bytes

@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

Irritantemente, expressões em lote geralmente não gostam de variáveis ​​vazias. Editar: salvou 1 byte graças a @ CᴏɴᴏʀO'Bʀɪᴇɴ e 2 bytes graças a @ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ (e vários bytes em outras respostas também, embora ainda não creditados).


Eu acho que você pode remover um espaço entre calle: x`, não?
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Huh, então você pode. Eu tenho um monte de respostas que precisam ser atualizadas nesse caso ...
Neil

2

Python 2, 265 260 254 bytes

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

Python, 142 137 bytes

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

Bash, 41 bytes

Esse script bash tem o efeito colateral de criar diretórios se eles não existirem, mas deve atender aos requisitos. Obrigado Karl e Neil por suas melhorias.

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

Uso: bash getpath.sh "absolute" "new"

Se você não gostar do stderr quando o segundo argumento for uma sequência vazia, poderá testá-lo da seguinte forma (48 bytes):

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

Tentativa anterior de 30 bytes (requer a existência de diretórios): cd $ 1; [$ 2] && cd $ 2; echopwd


A pergunta diz que os comandos devem funcionar, se os diretórios passados ​​realmente existem ou não na sua máquina.
Dennis

Ah entendo. Que pena.
Bryn

Olá, e bem-vindo ao PPCG! Normalmente, se sua resposta não funcionar, você a exclui. Você pode clicar no link excluir acima deste comentário.
NoOneIsHere

Você poderia mkdir -pter certeza de que eles existem.
1913 Karl Napf

Obrigado, estou tentando uma versão com mkdir. Excluirei esta resposta e adicionarei uma nova, se eu descobrir.
Bryn

1

C #, 43 bytes

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

Guardado 1 byte graças a @aloisdg

Path.Combinereúne os argumentos e Path.GetFullPathresolve os ..\s


Olá, e bem-vindo ao PPCG! Este não é um programa válido - inclua maine uma classe, ou altere-o para um lanbda: a,b->...
NoOneIsHere 16/16

Eu ia postar :) Bom primeiro envio! você pode remover o espaço após o seguinte ,: (x, y)=>(x,y)
aloisdg diz Reinstate Monica



1

Javascript, 210 bytes

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)}

Aqui está o conjunto de testes

Com quebras de linha em vez de ponto e vírgula:

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 bytes

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

normalizeé necessário para lidar com referências relativas. addé usado para manipular o segundo caminho que começa com /, que Paths.get(a, b)não manipula conforme especificado.


Olá, e bem-vindo ao PPCG! Este é um bom primeiro post!
NoOneIsHere

0

Bash, 38 bytes

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

Não requer privilégios de root e não faz suposições sobre arquivos, diretórios ou links simbólicos existentes ou não existentes.

Teste em Ideone .

Como funciona

[[ $2 = /* ]]testa se o segundo argumento da linha de comando começa com /.

Caso contrário, o caminho é relativo e p=$1define a variável p para o primeiro argumento da linha de comando.

Desta forma, $p/$2é /$2se $2é um caminho absoluto e $1/$2se ele é um realtive.

Por fim, realpath -sm $p/$2imprime o caminho absoluto canônico de $p/$2. O -scomutador faz com que o caminho real ignore os links simbólicos e os -mcomponentes ausentes do comutador.


0

Ruby, 16 bytes

Como aparentemente é permitido usar um método da biblioteca padrão :

File.expand_path

Veja a suíte de testes em repl.it .


Entrada através de variáveis não é permitido, mas a submissão função, são, o que significa que você deve cortá-lo File.expand_path:)
Nathan Merrill

Também recomendo testá-lo no conjunto de testes para garantir que funcione corretamente em todos os casos de teste.
18716 Nathan Merrill

@NathanMerrill eu fiz, mas vou em frente e colocarei algo no repl.it.
Jordan

Editado para incluir o link do conjunto de testes.
Jordan

0

GNU sed , 81 59 + 1 = 60 bytes

+1 byte para -rsinalizador. Espera que a entrada no STDIN separe por um único espaço.

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

Experimente online!

Explicação

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.