Объединение ряда компонентов путей в common lisp

Как мне соединить ряд компонентов пути в common lisp?

В питоне я могу сделать,

`os.path.join("/home/", username, "dira", "dirb", "dirc");`

Что было бы эквивалентно в common lisp?

Конечно, я могу написать свою собственную функцию, но я подозреваю, что смогу использовать что-то встроенное.


person ealfonso    schedule 23.06.2014    source источник
comment
Пути — это не то же самое, что строки. Когда создавался Common Lisp, способы представления путей в системах были немного более разнообразными, поэтому в языке есть несколько удобных функций для манипулирования именами путей. Как показывает Дирк, ваша задача становится намного проще, если вы используете пути и связанные с ними функции, а не строки.   -  person Joshua Taylor    schedule 23.06.2014


Ответы (2)


Если вы настаиваете на использовании строк для представления путей, то, похоже, не существует встроенного решения, кроме создания собственного.

(defun join-strings (list &key (separator "/") (force-leading nil))
  (let* ((length (length list))
         (separator-size (length separator))
         (text-size (reduce #'+ (mapcar #'length list) :initial-value 0))
         (size (+ text-size (* separator-size (if force-leading length (1- length)))))
         (buffer (make-string size)))
    (flet ((copy-to (position string)
             (loop
               :with wp := position
               :for char :across string 
               :do (setf (char buffer (prog1 wp (incf wp))) char)
               :finally (return wp))))
      (loop
        :with wp := 0
        :for string :in list
        :do (when (or force-leading (plusp wp)) (setf wp (copy-to wp separator)))
            (setf wp (copy-to wp string)))
      buffer)))

(join-strings '("home" "kurt" "source" "file.txt") :force-leading t)
==> "/home/kurt/source/file.txt"

Однако, если вы можете использовать пути, вы могли бы, например, делать:

(merge-pathnames #P"subdir1/subdir2/file.type" #P"/usr/share/my-app")
==> #P"/usr/share/my-app/subdir1/subdir2/file.type"

API путей также предоставляет функции для символического управления путями, извлечения компонентов пути и т. д.:

(pathname-directory #P"subdir1/subdir2/file.type")
==> '(:relative "subdir1" "subdir2")

(pathname-name #P"subdir1/subdir2/file.type")
==> "file"

(pathname-type #P"subdir1/subdir2/file.type")
==> "type"

(make-pathname :name "file" :type "type" :directory '(:relative "subdir1" "subdir2"))
==> #P"subdir1/subdir2/file.type"

В частности, компонент directory имени пути представлен в виде списка, поэтому вы можете использовать полный набор функций обработки списков для получения значений directory из других:

(make-pathname :directory (append '(:absolute "usr" "share") '("more" "stuff"))
               :name "packages" :type "lisp")
person Dirk    schedule 23.06.2014
comment
Примечание: в путях слияния наличие или отсутствие / для подкаталога (первый аргумент) имеет значение. - person Ehvince; 18.09.2020

Более простые строки соединения

(defun join-strings (lst sep)
  (if
   (atom lst)
   lst
   (reduce
    (lambda (a b)
      (concatenate 'string a sep b))
    (cdr lst)
    :initial-value (car lst))))
person Samantha Atkins    schedule 17.08.2020
comment
Я собирался предложить использовать :from-end T, чтобы избежать квадратичного поведения... но тогда, вероятно, этого не избежать. с путями это теоретическое, но вы дали своей функции это общее имя..... - person Will Ness; 19.08.2020