在clojure中给出相对路径的函数?

问题描述 投票:0回答:2

我需要一个函数,当给定基本目录和另一个路径时,我做了一个简化版本,仅匹配绝对路径,但希望也能够智能地处理“..”和“.”在路径中。我不确定最好的方法是什么

一些例子:

(relative-path "example" "example/hello") => "hello"

(relative-path "example" "../example/hello") => "hello"

(relative-path "example" "/usr/local") => "../../../usr/local"
clojure
2个回答
1
投票

经过一番尝试和错误,我想通了:

(require '[clojure.java.io :as io]
         '[clojure.string :as string])

(defn interpret-dots
  ([v] (interpret-dots v []))
  ([v output]
     (if-let [s (first v)]
       (condp = s
         "."  (recur (next v) output)
         ".." (recur (next v) (pop output))
         (recur (next v) (conj output s)))
       output)))

(defn drop-while-matching [u v]
  (cond (or (empty? u) (empty? v)) [u v]

        (= (first u) (first v))
        (recur (rest u) (rest v))

        :else [u v]))

(defn path-vector [path]
  (string/split (.getAbsolutePath (io/file path))
                (re-pattern (System/getProperty "file.separator"))))

(defn relative-path [root other]
  (let [[base rel] (drop-while-matching (interpret-dots (path-vector root))
                                        (interpret-dots (path-vector other)))]
    (if (and (empty? base) (empty? rel))
      "."
      (->> (-> (count base)
               (repeat "..")
               (concat rel))
           (string/join (System/getProperty "file.separator")))))

用途:

(relative-path "example/repack.advance/resources"
           "example/repack.advance/resources/eueueeueu/oeuoeu")
;;=> "eueueeueu/oeuoeu"

(relative-path "example/repack.advance/resources"
           "/usr/local")
;;=> "../../../../../../../../usr/local"

0
投票

我将 Java 解决方案改编为 Clojure:

(defn relative-path
  [a b]
  (let [path-a (.toPath (io/file a))
        path-b (.toPath (io/file b))
        can-relativize? (if (.getRoot path-a)
                          (some? (.getRoot path-b))
                          (not (.getRoot path-b)))]
    (when can-relativize?
      (str (.relativize path-a path-b)))))
(relative-path "example" "example/hello") => "hello"
(relative-path "example" "../example/hello") => "../../example/hello"
(relative-path "example" "/usr/local") => nil

请注意,只有当两个路径都有根或都没有根时,这才有效,因为这是 Path#relativize 的限制。

© www.soinside.com 2019 - 2024. All rights reserved.