พิมพ์พา ธ สัมพัทธ์


15

ลักษณะ

ให้เส้นทางต้นทางและเส้นทางปลายทางส่งออกเส้นทางสัมพัทธ์ไปยังปลายทางด้วยความเคารพต่อต้นทาง

กฎระเบียบ

  1. อินพุตอาจมาจาก stdin หรือเป็นอาร์กิวเมนต์ของโปรแกรม / ฟังก์ชัน

  2. ต้องรองรับทั้งพา ธ สไตล์ของ Windows และ Unix

  3. เส้นทางผลลัพธ์สามารถใช้/และ / หรือ\สำหรับตัวแยกเส้นทาง (ตัวเลือกและการรวมกันของทั้งคู่ของคุณเป็นปกติ)

  4. คุณสามารถถือว่าเส้นทางสัมพัทธ์เป็นไปได้

  5. ห้ามใช้โปรแกรมภายนอกฟังก์ชันในตัวหรือไลบรารีที่สร้างขึ้นเพื่อคำนวณเส้นทางสัมพัทธ์ (เช่น Python os.path.relpath)

  6. นี่คือ

    แก้ไข:กฎใหม่จากความคิดเห็น

  7. เส้นทางสัมพัทธ์ต้องเป็นเส้นทางสัมพัทธ์สั้นที่สุดเท่าที่จะเป็นไปได้

  8. สมมติว่าเส้นทางปลายทางนั้นแตกต่างจากเส้นทางต้นทาง

ตัวอย่างที่ 1

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

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

ตัวอย่างที่ 2

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

# Out
..\WindowsPowerShell\v1.0

เกี่ยวกับกฎ # 3 - ส่วนผสมก็โอเคไหม ../../vim\vim73\ftpluginเช่น
Duncan Jones

1
เราต้องกลับเส้นทางสัมพัทธ์ที่สั้นที่สุดหรือมันโอเคที่จะให้เส้นทางใด ๆ ?
Howard

@ ดันแคนใช่มิกซ์ก็โอเค
Rynant

1
@Howard มันจะต้องเป็นเส้นทางที่สั้นที่สุด
Rynant

ไม่ควรตัวอย่างแรกจะเป็น../vim/vim73/ftplugin?
Martijn

คำตอบ:


2

CJam, 46 ไบต์

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

ลองออนไลน์

ตัวอย่าง

$ 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

มันทำงานอย่างไร

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
มันมีข้อผิดพลาด ลองด้วย/aa/x /ab/y
jimmy23013

@ user23013: แก้ไขแล้ว
Dennis

2

Bash + coreutils, 116

นี่คือเชลล์สคริปต์เพื่อให้ลูกบอลกลิ้ง ค่อนข้างแน่ใจว่าจะมีคำตอบสั้นลง:

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

เอาท์พุท:

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

หมายเหตุไม่มีวิธีใดที่สคริปต์จะบอกได้ว่าสตริงนั้นหรือไม่ ftpluginนั้นเป็นไฟล์หรือไดเรกทอรี คุณอาจระบุไดเรกทอรีอย่างชัดเจนด้วยการต่อท้ายด้วย/ตัวอย่างในตัวอย่างด้านบน

จะไม่จัดการกับเส้นทางที่มีช่องว่างหรือตัวละครตลกอื่น ๆ ไม่แน่ใจว่าเป็นข้อกำหนดหรือไม่ ต้องการราคาพิเศษเพียงไม่กี่คำ


2

Javascript (E6) 104

แก้ไขการแจ้งเตือนที่เพิ่มเข้ามาสำหรับการส่งออก

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

Ungolfed

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

ทดสอบ

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

Ruby> = 1.9, 89 94 ตัวละคร

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

อินพุตผ่านอาร์กิวเมนต์บรรทัดรับคำสั่ง ใช้ได้ทั้งพา ธ แบบ UNIX และ Windows รวมถึงพา ธ ที่มีชื่อโฟลเดอร์ซ้ำ:

$ 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 ถ่าน

ฟังก์ชั่นรับเส้นทางเก่าทางซ้ายและเส้นทางใหม่ทางด้านขวา

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

วิธีการแก้ปัญหานี้มาในสามส่วนดูเหมือนpost@loop&pre~ว่า อธิบายโดยการระเบิด:

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

โปรดทราบว่าเราเพิ่มผู้นำ/ในแต่ละเส้นทางก่อนที่จะแยกเพื่อให้เราจัดการเส้นทางสไตล์ Windows โดยทำให้C:เป็น "โฟลเดอร์" สิ่งนี้ส่งผลให้โฟลเดอร์ว่างที่จุดเริ่มต้นของเส้นทางสไตล์ Unix แต่ที่ได้รับการลบออกโดยวง

ดูการทำงานจริง:

   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

นอกจากนี้คุณยังสามารถลองด้วยตัวคุณเองที่tryj.tk


2

Bash, 69 66

ฉันไม่ได้โพสต์สิ่งนี้เพราะฉันคิดว่าบางคนต้องสามารถทำได้ดีกว่านี้มาก แต่เห็นได้ชัดว่าไม่ใช่เรื่องง่าย

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

Nทำให้sedตรงกับสองบรรทัดด้วยกัน การแสดงออกครั้งแรกเอาคำนำหน้าทั่วไปลงท้ายด้วยหรือ/ \นิพจน์ที่สองแทนที่ชื่อไดเรกทอรีด้วย..ในบรรทัดแรก ในที่สุดมันก็เชื่อมต่อสองบรรทัดเข้ากับตัวคั่น

ขอบคุณ Hasturkun สำหรับตัวละคร 3 ตัว


ดูน่าสนใจ! คุณสามารถเพิ่มคำอธิบายได้ไหม?
Digital Trauma

1
@DigitalTrauma เพิ่มแล้ว แต่โดยพื้นฐานแล้วมันเป็นเพียงการแสดงออกปกติ
jimmy23013

ขอบคุณ! ฉันจะเล่นกับครั้งต่อไปฉันอยู่ที่อาคารผู้โดยสาร
Digital Trauma

คุณไม่จำเป็นต้องเรียกใช้sedสองครั้งคุณสามารถทำได้ด้วยสคริปต์เดียว
Hasturkun

@Hasturkun แต่ฉันไม่พบวิธีที่จะใช้งานNได้ บางทีคุณสามารถแก้ไขคำตอบนี้ถ้าคุณรู้วิธี
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 ตัวอักษรโดยไม่มีแบ็กสแลช
bebe

ขอบคุณ! แต่กฎที่ 2 บอกว่าต้องรองรับทั้งคู่ มันอยู่ในผลลัพธ์ที่ฉันสามารถเลือกอย่างใดอย่างหนึ่ง (กฎ 3)
kwokkie

1

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

ตัวอย่าง:

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

อาจมีวิธีที่สั้นกว่าในการทำ line 1 ด้วยexecและการดำเนินการกับสายอักขระ?
xnor

@xnor บางที แต่ฉันไม่เห็น
grc

สามารถใช้map(input,' ')งาน `(อินพุต (), อินพุต ()) ได้หรือไม่ (ฉันไม่สามารถทดสอบด้วยตัวเองได้)
xnor

@xnor ใช่นั่นขอบคุณ
grc

1

ทับทิม - 89

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

การใช้งาน:

ruby relative.rb working/directory destination/directory

3
นี้ล้มเหลวสำหรับข้อโต้แย้งเหมือนและ/foo/bar/foo/bar /foo/qux/foo/bar
Ventero

และล้มเหลวสำหรับเส้นทางลักษณะของ windows
edc65

@ edc65 กฎไม่ได้บอกว่าจำเป็นต้องสนับสนุนรูปแบบพา ธ ทั้งสองคุณสามารถทำได้
nderscore

@nderscore Rule 2 ต้องรองรับพา ธ สไตล์ Windows และ Unix
edc65

1
@Jwosty: นั่นคือความงามใช่มั้ย หาวิธีแก้ปัญหาที่สั้นและถูกต้อง ในอดีตฉันมีกรณีที่ฉันต้องแก้ไขคำตอบทั้งหมดเพราะกรณีที่ถูกมองข้าม ตอนนี้ในกรณีนี้ฉันใส่ความผิดบางส่วนในงานเช่นกันเพราะฉันเชื่อว่าชุดทดสอบที่เป็นของแข็งควรมาพร้อมกับงานทุกอย่าง แต่ก็ดี
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("/")}

แยกวิเคราะห์รูปแบบพา ธ แต่ส่งออกด้วย/ตัวคั่น

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

Ungolfed:

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

คำตอบของคุณไม่ถูกต้อง ลองทำสิ่งนี้กับ dirs และรวมกันcdเป็นหนึ่งเดียวกัน :)
core1024

0

Groovy - 144 ตัวอักษร

ทางออกหนึ่ง:

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

เอาท์พุทตัวอย่าง:

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

ungolfed:

// 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}"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.