elisp एमएसीएस लिस्प में एक ही पूर्ण पथ में कई पथ घटकों में शामिल होने का सही तरीका क्या है?




filenames path-manipulation (4)

मान लीजिए कि मेरे पास चर और file जिनमें क्रमशः एक निर्देशिका और एक फ़ाइलनाम का प्रतिनिधित्व करने वाले तार हैं। इमैक लिस्प में उचित तरीका क्या है जो उन्हें फाइल में पूर्ण पथ में शामिल कर सकता है?

उदाहरण के लिए, यदि dir "/usr/bin" और file "ls" , तो मुझे "/usr/bin/ls" । लेकिन अगर इसके बजाय dir "/usr/bin/" , तो मैं अभी भी वही चीज चाहता हूं, जिसमें कोई दोहराव नहीं है।


मैं एक पथ पर कई नेस्टेड निर्देशिकाओं में शामिल होना चाहता था। मूल रूप से मैंने कई expand-file-name कॉल का उपयोग किया, जैसे:

(expand-file-name "b" (expand-file-name "a" "/tmp"))
"/tmp/a/b"

हालांकि यह बल्कि क्रिया है, और पीछे की ओर पढ़ता है।

इसके बजाय मैंने एक फ़ंक्शन लिखा जो पायथन के os.path.join की तरह काम करता है:

(defun joindirs (root &rest dirs)
  "Joins a series of directories together, like Python's os.path.join,
  (dotemacs-joindirs \"/tmp\" \"a\" \"b\" \"c\") => /tmp/a/b/c"

  (if (not dirs)
      root
    (apply 'joindirs
           (expand-file-name (car dirs) root)
           (cdr dirs))))

यह इस तरह काम करता है:

(joindirs "/tmp" "a" "b")
"/tmp/a/b"
(joindirs "~" ".emacs.d" "src")
"/Users/dbr/.emacs.d/src"
(joindirs "~" ".emacs.d" "~tmp")
"/Users/dbr/.emacs.d/~tmp"

यदि आप एक सुविधाजनक फ़ाइल और निर्देशिका हेरफेर लाइब्रेरी f.el , तो आपको केवल f-join आवश्यकता है। नीचे दिया गया कोड उन लोगों के लिए है, जो किसी कारण से इस पुस्तकालय का उपयोग करने से इनकार करते हैं।

(defun os-path-join (a &rest ps)
  (let ((path a))
    (while ps
      (let ((p (pop ps)))
        (cond ((string-prefix-p "/" p)
               (setq path p))
              ((or (not path) (string-suffix-p "/" p))
               (setq path (concat path p)))
              (t (setq path (concat path "/" p))))))
    path))

यह बिल्कुल पायथन के os.path.join रूप में व्यवहार करता है।

ELISP> (os-path-join "~" "a" "b" "")
"~/a/b/"
ELISP> (os-path-join "~" "a" "/b" "c")
"/b/c"

Emacs 24.4 से पहले string-suffix-p मौजूद नहीं है, इसलिए मैंने अपनी खुद की जाँच में लिखा है कि क्या कोई स्ट्रिंग Emacs Lisp में किसी प्रत्यय के साथ समाप्त होती है ।


आप इसके लिए expand-file-name उपयोग कर सकते हैं:

(expand-file-name "ls" "/usr/bin")
"/usr/bin/ls"
(expand-file-name "ls" "/usr/bin/")
"/usr/bin/ls"

संपादित करें: यह केवल निरपेक्ष निर्देशिका नामों के साथ काम करता है। मुझे लगता है कि ट्रे का जवाब बेहतर समाधान है।


यहाँ मेरा उपयोग है:

(defun catdir (root &rest dirs)
  (apply 'concat (mapcar
          (lambda (name) (file-name-as-directory name))
          (push root dirs))))

@ Dbr से अंतर:

  1. एक "emacs निर्देशिका नाम" लौटाता है, यानी एक अनुगामी स्लैश के साथ एक मूल्य
  2. यह root का विस्तार नहीं करता है यदि root सापेक्ष है (नोट देखें)
  3. root को root रूप में मानते हैं, जबकि joindirs root रूप में "/" शुरू होने वाले पहले घटक का उपयोग करेंगे।

टिप्पणियाँ

कई फ़ाइल हैंडलिंग फ़ंक्शंस (सभी, अधिकांश, ???) निरर्थक स्लैश को सामान्य करेंगे और रिश्तेदार पथों पर expand-file-name (या समान) कॉल करेंगे, इसलिए # 2 और # 3 वास्तव में कोई फर्क नहीं पड़ सकता है।