import UIKit import XCPlayground enum Path: Equatable { case Current case Parent case Root case Letter(String) } extension Path: CustomStringConvertible { var description: String { switch self { case .Current: return "./" case .Parent: return "../" case .Root: return "/" case let .Letter(p): return p + "/" } } } func ==(lhs: Path, rhs: Path) -> Bool { switch lhs { case .Root: switch rhs { case .Root: return true default: return false } case .Parent: switch rhs { case .Parent: return true default: return false } case .Current: switch rhs { case .Current: return true default: return false } case let .Letter(letter): switch rhs { case let .Letter(retter): return letter == retter default: return false } } } struct URLExpression { private(set) var paths: [Path] = [] init(path: String) { if path[path.startIndex] == "/" { self.paths.append(.Root) } for p in (path.characters.split { $0 == "/" }) { let p = String(p) switch p { case ".": if self.paths.count == 0 { self.paths.append(.Current) } case "..": if let last = self.paths.last { switch last { case .Parent: self.paths.append(.Parent) default: self.paths.removeLast() } } else { self.paths.append(.Parent) } default: self.paths.append(.Letter(p)) } } if self.paths.count == 0 { self.paths.append(.Current) } } init(url: NSURL) { if let path = url.path { let host = url.host ?? "" self.init(path: host + path) } else { self.init(path: "/") } } init() { } } extension URLExpression: SequenceType { var count: Int { return self.paths.count } var first: Path? { return self.paths.first } var last: Path? { return self.paths.last } subscript(idx: Int) -> Path { return self.paths[idx] } func generate() -> IndexingGenerator<[Path]> { return self.paths.generate() } } extension URLExpression { func traverseTo(to: URLExpression) -> URLExpression { var ret = URLExpression() if to[0] == .Root { var idx = 0 for (i, (l, r)) in zip(self, to).enumerate() { print(i) if l == r { idx++ } else { idx = i break } } print(idx) for _ in self.paths[idx..<self.count] { ret.paths.append(.Parent) } if self.count == idx { ret.paths.append(.Current) } for p in to.paths[idx..<to.count] { switch p { case .Current: break case .Root: break default: ret.paths.append(p) } } } else { ret.paths = self.paths for p in to { switch p { case .Parent: if ret.last != .Root { ret.paths.removeLast() } case .Current: break default: ret.paths.append(p) } } } return ret } } extension URLExpression: CustomStringConvertible { var description: String { return self.paths.reduce("", combine: { i, p in i + p.description }) } } let url = "ddd://dd/../../../../pp/./c/../.." let uuu = NSURL(string: url) uuu?.URLByStandardizingPath uuu?.host uuu?.path let ex = URLExpression(url: NSURL(string: url)!) ex.description let from = URLExpression(path: "/Users/user/../Documents") let to = URLExpression(path: "../../Users/user/../Documents") let ret = from.traverseTo(to) ret.description to.traverseTo(from)