目录计算


19

对于此挑战,将为您提供一条绝对路径和一条“新”路径(可以是绝对路径,也可以是相对路径),并且您需要返回最终路径。

例如,如果您当前的目录是/var/tmp/test

my_dir 要么 my_dir/ 应返回/var/tmp/test/my_dir

../../my_dir 应该回来 /var/my_dir

/my_dir/./ 应该回来 /my_dir

../../../../../ 应该回来 /

要更加学究:

  • 目录是由字母数字字符的非空字符串和符号-_.
  • 路径是0或多个目录的列表,用分隔/。绝对路径以a开头/,相对路径则不是。路径可以包含结尾/

给定第一个路径,您需要“解析”第二个路径。

解决的过程是:

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

这是一个,所以请使用您喜欢的语言尽可能短地提交!


某些答案似乎是假定机器上存在与目录树的任何部分同名的文件(或符号链接)。可以吗
丹尼斯

我们可以按照我们希望的任何顺序进行两个输入吗?
Downgoat

愚蠢的问题...我可以有副作用吗?具体来说,有诸如um mkdir $patha; cd $patha; mkdir $pathb; cd $pathb; echo `abspath`(或其他)之类的副作用吗?

@丹尼斯。程序的输出应独立于文件系统
Nathan Merrill

@downgoat很好
Nathan Merrill

Answers:



3

Python,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

烦人的批处理表达式通常不喜欢空变量。编辑:感谢@CᴏɴᴏʀO'Bʀɪᴇɴ保存了1个字节,感谢@EʀɪᴋᴛʜᴇGᴏʟғᴇʀ保存了2个字节(以及其他答案上的一堆字节,尽管很可惜)。


我认为您可以在call和:x` 之间删除空格,不是吗?
科纳·奥布莱恩

@CᴏɴᴏʀO'Bʀɪᴇɴ嗯,可以。在这种情况下,我有很多答案需要更新……
Neil

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

Python,第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

Bash,41个字节

如果目录不存在,则此bash脚本具有创建目录的副作用,但应满足要求。感谢KarlNeil的改进。

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确保它们存在。
Karl Napf

谢谢,我正在尝试使用mkdir版本。如果知道了,我将删除此答案并添加一个新答案。
布林

1

C#,43个字节

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

@aloisdg节省了1个字节

Path.Combine将参数放在一起,并Path.GetFullPath解决..\s


您好,欢迎来到PPCG!这不是有效的程序-包含main和一个类,或将其更改为lanbda:a,b->...
NoOneIsHere16年

我打算将其发布:)不错的初稿!你可以以后删除空格,(x, y)=>(x,y)
aloisdg说恢复莫妮卡

另外,高尔夫线程C#技巧也可能使您感兴趣。
aloisdg说恢复莫妮卡


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

Bash,38个字节

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

不需要root特权,也不对现有或不存在的文件,目录或符号链接进行任何假设。

Ideone上进行测试

怎么运行的

[[ $2 = /* ]]测试第二个命令行参数是否以开头/

如果不是,则路径为相对路径,p=$1并将变量p设置为第一个命令行参数。

这种方式$p/$2是,/$2如果$2是一条绝对路径,$1/$2如果它是一条现实路径。

最后,realpath -sm $p/$2打印的规范绝对路径$p/$2。该-s开关使真实路径忽略符号链接,以及-m开关缺少的组件。


0

Ruby,16个字节

由于显然允许使用标准库中的方法

File.expand_path

请参阅repl.it上测试套件


不允许通过变量输入,但允许函数提交,这意味着您应将其缩短为File.expand_path:)
Nathan Merrill

我还建议针对测试套件进行实际测试,以确保它在所有测试用例上都能正常工作。
内森·梅里尔

@NathanMerrill我做到了,但我会继续在repl.it上粘贴一些内容。
约旦

编辑以包括测试套件链接。
约旦

0

GNU sed81 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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.