「お題:フルパスから相対パスを求める」をjsでやってみた男
説明
二つのフルパスを受け取り、一つ目のパスから二つ目のパスへの相対パスを返す関数を実装せよ。条件)
・パス区切り文字は / のみサポートする。
・結果パスは カレントディレクトリを表す ./ もしくは、一つ親のディレクトリを表す ../ から始める。
・パスが / で終わる場合ディレクトリとする。
・パスが / で終わらない場合ファイルとする。
・空のパス(空文字列、null、nilなど)が渡された場合、エラーとする。
・パス区切り文字以外でファイル名として使用不可能な文字(参照:http://goo.gl/R0LqY)が含まれている場合、エラーとする。例1) 同じディレクトリにあるファイル
パス1:/aaa/bbb/from.txt
パス2:/aaa/bbb/to.txt
結果 :./to.txt例2) 親ディレクトリにあるファイル
パス1:/aaa/bbb/from.txt
パス2:/aaa/to.txt
結果 :../to.txt例3) 子ディレクトリにあるファイル
パス1:/aaa/bbb/from.txt
パス2:/aaa/bbb/ccc/to.txt
結果 :./ccc/to.txt例4) 親の子の子にあるファイル
パス1:/aaa/bbb/from.txt
パス2:/aaa/ccc/ddd/to.txt
結果 :../ccc/ddd/to.txt例5) ルート越え
パス1:/aaa/bbb/from.txt
パス2:/ddd/ccc/to.txt
結果 :../../ddd/ccc/to.txt例6) ディレクトリからファイル
パス1:/aaa/bbb/
パス2:/aaa/ddd/to
結果 :../ddd/to例7) ファイルからディレクトリ
パス1:/aaa/bbb/from
パス2:/aaa/ccc/
結果 :../ccc/例8) ディレクトリからディレクトリ
パス1:/aaa/bbb/
パス2:/aaa/ccc/
結果 :../ccc/例9) 同じパス
パス1:/aaa/bbb/ccc.txt
パス2:/aaa/bbb/ccc.txt
結果 :./ccc.txt例10) 空
パス1:空
パス2:/bbb/to.txt
結果 :エラー例11) 使用不可能な文字
パス1:/aaa/g*
パス2:/bbb/to.txt
結果 :エラー
jsでやる
前回同様どううまくやるかという話ですが、やはり思いつきませんでした。for万歳
尚、どうすればいいかよくわからなかった点は以下のように勝手に決めました。
- スラッシュが連続したらエラー
- 先頭にスラッシュが無かったらエラー
function relativePath(from, to) { if ([from, to].some(RegExp.prototype.test, /^[^\/]|\.$|^$|[\\\?\*\:\|"<>]|\/\//)) return "エラー"; var f = from.substr(1).split("/"), t = to.substr(1).split("/"); for (var i = 0, l = Math.min(f.length, t.length) - 1; i < l && f[i] === t[i]; ++i); return ((new Array(f.length - i)).join("../") || "./") + t.slice(i).join("/"); } //test alert( [ ["/aaa/bbb/from.txt", "/aaa/bbb/to.txt", "./to.txt"], ["/aaa/bbb/from.txt", "/aaa/to.txt", "../to.txt"], ["/aaa/bbb/from.txt", "/aaa/bbb/ccc/to.txt", "./ccc/to.txt"], ["/aaa/bbb/from.txt", "/aaa/ccc/ddd/to.txt", "../ccc/ddd/to.txt"], ["/aaa/bbb/from.txt", "/ddd/ccc/to.txt", "../../ddd/ccc/to.txt"], ["/aaa/bbb/", "/aaa/ddd/to", "../ddd/to"], ["/aaa/bbb/from", "/aaa/ccc/", "../ccc/"], ["/aaa/bbb/", "/aaa/ccc/", "../ccc/"], ["/aaa/bbb/ccc.txt", "/aaa/bbb/ccc.txt", "./ccc.txt"], ["", "/bbb/to.txt", "エラー"], ["/aaa/g*", "/bbb/to.txt", "エラー"] ].every(function (a) { return relativePath(a[0], a[1]) === a[2]; }) );