In đường dẫn tương đối


15

Sự miêu tả

Đưa ra một đường dẫn nguồn và một đường dẫn đích, xuất ra đường dẫn tương đối đến đích đối với nguồn đó.

Quy tắc

  1. Đầu vào có thể đến từ stdin hoặc làm đối số cho chương trình / hàm.

  2. Cả hai đường dẫn kiểu Windows và Unix đều phải được hỗ trợ.

  3. Đường dẫn đầu ra có thể sử dụng /và / hoặc \cho dấu phân cách đường dẫn (sự lựa chọn và kết hợp cả hai của bạn là OK).

  4. Bạn có thể giả sử một con đường tương đối là có thể.

  5. Việc sử dụng các chương trình bên ngoài, các hàm tích hợp hoặc thư viện được tạo để tính toán các đường dẫn tương đối đều bị cấm (ví dụ: Python os.path.relpath)

  6. Đây là

    Chỉnh sửa: Quy tắc mới từ ý kiến.

  7. Đường dẫn tương đối phải là đường dẫn tương đối ngắn nhất có thể.

  8. Giả sử đường dẫn đích khác với đường dẫn nguồn.

ví dụ 1

# In
/usr/share/geany/colorschemes
/usr/share/vim/vim73/ftplugin

# Out
../../vim/vim73/ftplugin

Ví dụ 2

# In
C:\Windows\System32\drivers
C:\Windows\System32\WindowsPowerShell\v1.0

# Out
..\WindowsPowerShell\v1.0

Về quy tắc số 3 - là một hỗn hợp ok? Ví dụ ../../vim\vim73\ftplugin.
Duncan Jones

1
Chúng ta có phải trả lại con đường tương đối ngắn nhất không hay có ổn không?
Howard

@Duncan Vâng, một hỗn hợp là ok.
Rynant

1
@Howard, nó phải là con đường tương đối ngắn nhất.
Rynant

không nên là ví dụ đầu tiên ../vim/vim73/ftplugin?
Martijn

Câu trả lời:


2

CJam, 46 byte

ll]{'\/'/f/:~}/W{)__3$=4$@==}g@,1$-"../"*o>'/*

Hãy thử trực tuyến.

Ví dụ

$ echo '/usr/share/geany/colorschemes
> /usr/share/vim/vim73/ftplugin' | cjam path.cjam; echo
../../vim/vim73/ftplugin
$ echo 'C:\Windows\System32\drivers
> C:\Windows\System32\WindowsPowerShell\v1.0' | cjam path.cjam; echo
../WindowsPowerShell/v1.0

Làm thế nào nó hoạt động

ll]         " Read two lines from STDIN and wrap them in an array.                       ";
{           " For each line:                                                             ";
  '\/       " Split by “\”.                                                              ";
  '/f/      " Split each chunk by “/”.                                                   ";
  :~        " Flatten the array of chunks.                                               ";
}/          "                                                                            ";
W           " Push -1 (accumulator).                                                     ";
{           "                                                                            ";
  )__       " Increment and duplicate twice.                                             ";
  3$=       " Extract the corresponding chunk from the first line.                       ";
  4$@=      " Extract the corresponding chunk from the second line.                      ";
  =         " If the are equal,                                                          ";
}g          " repeat the loop.                                                           ";
@,          " Rotate the array of chunks of the first line on top and get its length.    ";
1$-         " Subtract the value of the accumulator.                                     ";
"../"*o     " Print the string “../” repeated that many times.                           ";
>           " Remove all chunks with index less than the accumulator of the second line. ";
'/*         " Join the chunks with “/”.                                                  ";

1
Nó có một lỗi. Hãy thử /aa/xvới /ab/y.
jimmy23013

@ user23013: Đã sửa.
Dennis

2

Bash + coreutils, 116

Đây là một kịch bản shell để có được quả bóng lăn. Khá chắc chắn rằng sẽ có câu trả lời ngắn hơn:

n=`cmp <(echo $1) <(echo $2)|grep -Po "\d+(?=,)"`
printf -vs %`grep -o /<<<${1:n-1}|wc -l`s
echo ${s// /../}${2:n-1}

Đầu ra:

$ ./rel.sh /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../vim/vim73/ftplugin
$ ./rel.sh /usr/share/geany/colorschemes/ /usr/share/vim/vim73/ftplugin/
../../vim/vim73/ftplugin/
$ ./rel.sh /usr/share/vim/vim73/ftplugin /usr/share/geany/colorschemes
../../geany/colorschemes
$ 

Lưu ý rằng không có cách nào để tập lệnh cho biết chuỗi đó ftpluginlà tệp hay thư mục. Bạn có thể cung cấp một thư mục rõ ràng bằng cách nối nó với một /ví dụ như trong ví dụ trên.

Không xử lý các đường dẫn chứa khoảng trắng hoặc các ký tự vui nhộn khác. Không chắc đó có phải là yêu cầu hay không. Chỉ cần một vài trích dẫn thêm là cần thiết.


2

Javascript (E6) 104

Chỉnh sửa thêm cảnh báo cho đầu ra

R=(s,d)=>alert(s.split(x=/\/|\\/).map(a=>a==d[0]?d.shift()&&'':'../',d=d.split(x)).join('')+d.join('/'))

Ung dung

R (s,d) => // a single espression is returned, no {} or () needed
  s.split(x=/\/|\\/) // split string at / or \, save regexp in X for later
  .map( // create a new array from s
     a => a == d[0] // check if current of s and d equals
          ? d.shift() && '' // map to '' and cut 1 element of d
          : '../', // else map to '../'
     d=d.split(x)) // second param of map is useless, so split d here
  .join('')+d.join('/') // join map and concat to rest of d adding separators

Kiểm tra

R('C:\\Windows\\System32\\drivers','C:\\Windows\\System32\\WindowsPowerShell\\v1.0')

../WindowsPowerShell/v1.0

R('/usr/share/geany/colorschemes','/usr/share/vim/vim73/ftplugin')

../../vim/vim73/ftplugin


2

Hồng ngọc> = 1,9, 89 94 nhân vật

$;=/\\|\//
a,b=$*.map &:split
puts"../"*(a.size-r=a.index{a[$.+=1]!=b[$.]}+1)+b[r..-1]*?/

Nhập thông qua các đối số dòng lệnh. Hoạt động cho cả đường dẫn kiểu UNIX và Windows, bao gồm đường dẫn có tên thư mục lặp lại:

$ ruby relpath.rb /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../../vim/vim73/ftplugin
$ ruby relpath.rb 'C:\Windows\System32\drivers' 'C:\Windows\System32\WindowsPowerShell\v1.0'
../WindowsPowerShell/v1.0
$ ruby relpath.rb /foo/bar/foo/bar /foo/qux/foo/bar
../../../qux/foo/bar

2

J - 63 char

Một hàm lấy đường dẫn cũ ở bên trái và đường dẫn mới ở bên phải.

}.@;@(c=.c&}.`(,~(<'/..')"0)@.(~:&{.))&('/'<;.1@,'\/'&charsub)~

Giải pháp này có ba phần, trông như thế post@loop&pre~. Giải thích bằng vụ nổ:

post @ loop & pre ~   NB. the full golf
                  ~   NB. swap the arguments: new on left, old on right
            & pre     NB. apply pre to each argument
       loop           NB. run the recursive loop on both
post @                NB. apply post to the final result

'/'<;.1@,'\/'&charsub  NB. pre
         '\/'&charsub  NB. replace every \ char with /
'/'     ,              NB. prepend a / char
   <;.1@               NB. split string on the first char (/)

c=.c&}.`(,~(<'/..')"0)@.(~:&{.)  NB. loop
                      @.(~:&{.)  NB. if the top folders match:
    &}.                          NB.   chop off the top folders
   c                             NB.   recurse
       `                         NB. else:
           (<'/..')"0            NB.   change remaining old folders to /..
         ,~                      NB.   append to front of remaining new folders
c=.                              NB. call this loop c to recurse later

}.@;  NB. post
   ;  NB. turn the list of folders into a string
}.@   NB. chop off the / in the front

Lưu ý rằng chúng tôi thêm một đường dẫn /vào từng đường dẫn trước khi tách, để chúng tôi xử lý các đường dẫn kiểu Windows bằng cách tạo C:thành một "thư mục". Điều này dẫn đến một thư mục trống khi bắt đầu các đường dẫn kiểu Unix, nhưng luôn bị xóa bởi vòng lặp.

Xem nó trong hành động:

   NB. you can use it without a name if you want, we will for brevity
   relpath =. }.@;@(c=.c&}.`(,~(<'/..')"0)@.(~:&{.))&('/'<;.1@,'\/'&charsub)~
   '/usr/share/geany/colorschemes' relpath '/usr/share/vim/vim73/ftplugin'
../../vim/vim73/ftplugin
   'C:\Windows\System32\drivers' relpath 'C:\Windows\System32\WindowsPowerShell\v1.0'
../WindowsPowerShell/v1.0

Bạn cũng có thể thử nó cho mình tại tryj.tk .


2

Bash, 69 66

Tôi đã không đăng bài này vì tôi nghĩ ai đó phải có khả năng làm tốt hơn nhiều. Nhưng rõ ràng nó không phải là dễ dàng.

sed -r 'N;s/(.*[/\])(.*)\n\1/\2\n/'|sed '1s/[^/\]*/../g;N;s!\n!/!'

Nlàm cho sedkhớp hai dòng với nhau. Biểu thức đầu tiên loại bỏ tiền tố phổ biến kết thúc bằng /hoặc \. Biểu thức thứ hai thay thế tên thư mục bằng ..trong dòng đầu tiên. Cuối cùng, nó nối hai dòng với dấu phân cách.

Cảm ơn Hasturkun cho 3 nhân vật.


Trông có vẻ thú vị! Bạn có thể thêm một lời giải thích?
Chấn thương kỹ thuật số

1
@DigitalTrauma Đã thêm. Nhưng về cơ bản chúng chỉ là những biểu hiện thông thường.
jimmy23013

Cảm ơn! Tôi sẽ chơi với điều này vào lần tới Tôi đang ở một nhà ga
Chấn thương kỹ thuật số

Bạn không thực sự cần phải chạy sedhai lần, bạn có thể làm điều này với một tập lệnh.
Hasturkun

@Hasturkun Nhưng tôi không tìm ra cách để nó hoạt động N. Có lẽ bạn có thể chỉnh sửa câu trả lời này nếu bạn biết cách.
jimmy23013

1

C, 119 106

void p(char*s,char* d){while(*s==*d){s++;d++;}s--;while(*s){if(*s==47||*s==92)printf("../");s++;}puts(d);}

p(char*s,char*d){for(;*s;)*s++-*d?*s-47||printf("../"):d++;puts(d);}68 ký tự không có dấu gạch chéo ngược
bebe

Cảm ơn! Nhưng quy tắc 2 nói cả hai phải được hỗ trợ. Đó là trong đầu ra nơi tôi có thể chọn cái này hoặc cái kia (quy tắc 3).
kwokkie

1

Trăn 3, 120

a,b=(i.split('\\/'['/'in i])for i in map(input,'  '))
while[]<a[:1]==b[:1]:del a[0],b[0]
print('../'*len(a)+'/'.join(b))

Thí dụ:

$ python3 path.py
 /usr/share/geany/colorschemes
/usr/share/vim/vim73/ftplugin 
../../vim/vim73/ftplugin

Có thể có một cách ngắn hơn để thực hiện execcác hoạt động dòng 1 và chuỗi?
xnor

@xnor Có thể, nhưng tôi không thể nhìn thấy nó.
grc

Có thể map(input,' ')làm việc cho `(input (), input ()) không? (Tôi không thể tự kiểm tra)
xnor

@xnor Vâng, hoạt động cảm ơn!
grc

1

Hồng ngọc - 89

r=/\/|\\/
s = ARGV[0].split r
d = ARGV[1].split r
puts ("../"*(s-d).size)+((d-s).join"/")

Sử dụng:

ruby relative.rb working/directory destination/directory

3
Điều này không thành công cho các đối số như /foo/bar/foo/bar/foo/qux/foo/bar.
Ventero

Và thất bại cho các đường dẫn kiểu windows
edc65

@ edc65 Các quy tắc không nói rằng cần thiết để hỗ trợ cả hai định dạng đường dẫn, bạn có thể thực hiện một trong hai định dạng.
nderscore

@nderscore Quy tắc 2 Cả hai đường dẫn kiểu Windows và Unix phải được hỗ trợ.
edc65

1
@Jwosty: Chà, đó là vẻ đẹp phải không? Đưa ra một giải pháp vừa ngắn vừa đúng. Trước đây tôi đã có những trường hợp phải sửa lại câu trả lời hoàn toàn vì một trường hợp bị bỏ qua. Bây giờ, trong trường hợp này tôi cũng đổ lỗi một phần cho nhiệm vụ, bởi vì tôi tin rằng một tập hợp các trường hợp thử nghiệm chắc chắn sẽ đi kèm với mọi nhiệm vụ, nhưng tốt.
Joey

0

JavaScript - 155

function p(s,d){s=s.split(/\\|\//g);d=d.split(/\\|\//g);o=[];for(i=0;s[i]==d[i];i++);for(j=s.length-i;j--;)o[j]="..";return o.concat(d.slice(i)).join("/")}

Phân tích cú pháp định dạng đường dẫn nhưng đầu ra với /dấu phân cách.

console.log(p("/usr/share/geany/colorschemes","/usr/share/vim/vim73/ftplugin"));
../../vim/vim73/ftplugin
console.log(p("/usr/share/geany/colorschemes/test/this","/usr/share/vim/vim73/ftplugin/this/is/a/test"));
../../../../vim/vim73/ftplugin/this/is/a/test
console.log(p("c:\\windows\\system32\\drivers\\etc\\host","c:\\windows\\system\\drivers\\etc\host"));
../../../../system/drivers/etchost

0

PHP, 158 151

function r($a,$b){$a=explode('/',$a);$b=explode('/',$b);foreach($a as $k=>$v){if($v==$b[$k])$b[$k]='..';else break;}unset($b[0]);echo implode('/',$b);}

Ung dung:

function r($a,$b){
    $a=explode('/',$a);
    $b=explode('/',$b);
    foreach($a as $k=>$v){
        if($v==$b[$k])$b[$k]='..';
        else break; 
    }
    unset($b[0]);
    echo implode('/',$b);
}
// these lines are not included in count:
r('/test/test2/abc','/test/test3/abcd'); // ../test3/abcd
r('/test/test2/abc','/test/test2/abcd'); // ../../abcd

Câu trả lời của bạn không đúng. Hãy thử thực hiện các thư mục này và cdtạo từ cái này sang cái khác :)
core1024

0

Groovy - 144 ký tự

Một cách giải quyết:

x=args[0][1]!=':'?'/':'\\'
f={args[it].tokenize x}
s=f 0
d=f 1
n=0
while(s[n]==d[n++]);
u="..$x"*(s.size-(--n))
println "$u${d.drop(n).join x}"

đầu ra ví dụ:

bash$ groovy P.groovy C:\\Windows\\System32\\drivers C:\\Windows\\System32\\WindowsPowerShell\\v1.0
..\WindowsPowerShell\v1.0

bash$ groovy P.groovy /usr/share/geany/colorschemes /usr/share/vim/vim73/ftplugin
../../vim/vim73/ftplugin

bash$ groovy P.groovy /foo/bar/foo/bar /foo/qux/foo/bar
../../../qux/foo/bar

vô dụng:

// fs = file seperator, / or \
fs = args[0][1]!=':'?'/':'\\'

s = args[0].tokenize fs
d = args[1].tokenize fs

// n = # of matching dirs from root + 1
n = 0
while (s[n] == d[n++]) ;

// up = the up-prefix. e.g. "../../..", for instance 
n--
up = "..${fs}" * (s.size-n)

println "$up${d.drop(n).join fs}"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.