상대 경로를 인쇄하십시오


15

기술

소스 경로와 대상 경로가 주어지면 소스와 관련하여 대상에 대한 상대 경로를 출력하십시오.

규칙

  1. 입력은 stdin 또는 프로그램 / 기능에 대한 인수로 올 수 있습니다.

  2. Windows 및 Unix 스타일 경로가 모두 지원되어야합니다.

  3. 출력 경로는 경로 구분 기호를 사용 /하거나 및 / 또는 \경로 구분 기호로 사용할 수 있습니다 (두 가지를 모두 선택하고 조합해도됩니다).

  4. 상대 경로가 가능하다고 가정 할 수 있습니다.

  5. 상대 경로를 계산하기위한 외부 프로그램, 내장 또는 라이브러리 기능의 사용은 금지됩니다 (예 : Python 's 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

배쉬 + 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

자바 스크립트 (E6) 104

출력에 대한 추가 경고 편집

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

언 골프

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

루비> = 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

/분할하기 전에 각 경로에 행간 을 추가 C:하여 "폴더"로 만들어 Windows 스타일 경로를 처리 합니다. 이로 인해 유닉스 스타일 경로가 시작될 때 빈 폴더가 생성되지만 항상 루프에 의해 제거됩니다.

실제로보기 :

   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

배쉬, 69 66

나는 누군가가 훨씬 더 잘 할 수 있어야한다고 생각했기 때문에 이것을 게시하지 않았습니다. 그러나 분명히 쉽지 않습니다.

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

N차종은 sed두 개의 라인을 일치합니다. 첫 번째 표현식은 /또는로 끝나는 공통 접 두부를 제거합니다 \. 두 번째 표현식은 ..첫 번째 행에서 디렉토리 이름을 바꿉니다 . 마지막으로 두 줄을 구분 기호로 연결합니다.

3 명의 캐릭터를위한 Hasturkun에게 감사합니다.


재미있어 보인다! 설명을 추가 할 수 있습니까?
디지털 외상

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 2016 년

1

파이썬 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

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/barand와 같은 인수에 실패합니다 /foo/qux/foo/bar.
Ventero

그리고 Windows 스타일 경로에 실패
edc65

@ edc65 규칙에 따라 두 가지 경로 형식을 모두 지원할 필요는 없으며 둘 중 하나를 수행 할 수 있습니다.
nderscore

@nderscore 규칙 2 Windows 및 Unix 스타일 경로가 모두 지원되어야합니다.
edc65

1
@Jwosty : 음, 그게 아름다움인가요? 둘 다 짧은 솔루션을 생각해 냈습니다. 올바른. 과거에는 간과 사례로 인해 답변을 완전히 수정 해야하는 경우가있었습니다. 이제이 경우에는 모든 작업에 견고한 테스트 사례 세트가 포함되어야한다고 믿기 때문에 부분적으로 책임을 져야합니다.
Joey

0

자바 스크립트-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);}

언 골프 드 :

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

그루비-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

언 골프 :

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