缩短绝对路径


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
Nathan Merrill

Answers:


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字节

采用currying语法获取绝对路径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||'.'

测试用例


一个很好的把戏[a.length]!我可以借用它来改善我的Node.js答案吗?
齐柏林飞艇

@zeppelin好的。去吧!
Arnauld


5

ES6(Node.js REPL), 565446,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

@Downgoat Javascript lambdas作为一种答案而被广泛接受,因此我不明白为什么Node.js应该以不同的方式处理。
zeppelin

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字节添加到由Nathan Merrill提供的测试用例帐户


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

哦,要点。如今,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:".";

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.