【问题标题】:In Elisp, how to get path string with slash properly inserted?在 Elisp 中,如何正确插入斜线的路径字符串?
【发布时间】:2012-03-14 01:20:29
【问题描述】:

我通过连接部分路径和目录名称在 Elisp 中手动构建路径字符串。不幸的是,有时路径以斜线结尾,有时不是。因此,我需要在必要时在连接目录名称之前插入斜杠,否则不需要。有什么好方法可以做到这一点?

【问题讨论】:

  • 在 linux 上,文件路径中的加倍 // 符号通常(我一直认为)被解释为单个 /,所以有一个额外的 / 应该不是问题。
  • 这需要在所有平台上工作。

标签: emacs lisp elisp


【解决方案1】:

(file-name-as-directory dir) 将返回目录路径 dir 并带有一个斜杠,如果需要,添加一个,否则不添加。

如果您在列表中有部分路径序列,您可以执行以下操作:

(let ((directory-list '("/foo" "bar/" "p/q/" "x/y"))
      (file-name "some_file.el"))
  (concat
   (mapconcat 'file-name-as-directory directory-list "")
   file-name))

"/foo/bar/p/q/x/y/some_file.el"

或者,如果你想在列表中包含文件名,你可以使用directory-file-name,它与file-name-as-directory相反:

(let ((path-list '("/foo" "bar/" "p/q/" "x/y/some_file.el")))
  (mapconcat 'directory-file-name path-list "/"))

"/foo/bar/p/q/x/y/some_file.el"

(如果在非目录上使用directory-file-name 不可移植,请纠正我?)

【讨论】:

  • 如果它有一个以/ 开头的片段,例如"/p/q/"?
  • 如果是在开头,那么没有问题(按照我上面的例子)。如果不是在开头,那么绝对路径在路径组件序列的中间没有任何业务,因此这表明生成该序列的逻辑中存在错误。
  • 在第二个示例中明确使用“/”不是可移植性问题吗?
  • Clément:不,已经很长时间没有建议区分不同系统的目录分隔符了。旧的 directory-sep-char 变量在 Emacs 24 中已完全删除,但自版本 21 以来已被弃用。假设将使用生成的路径是 Emacs,您应该在所有系统上使用 / - Emacs 确保它工作。
【解决方案2】:

从可疑内容的部分组合文件名的最简单方法是使用扩展文件名。例如:

(expand-file-name "foo.txt")

这种常见的形式会给你一个基于默认目录的完整文件名:

/home/me/foo.txt

但如果你有一个变量 'dir' 的内容是 "/home/them/subdir" 并且想要使用它,请执行以下操作:

(expand-file-name "foo.txt" dir)

dir 是否以 / 结尾并不重要。如果您在其他平台上,并且包含另一个斜线,那么它也会做正确的事情。你有混音吗?把它们堆叠起来:

(expand-file-name "foo.txt" (expand-file-name "somesubdir" dir))

【讨论】:

    【解决方案3】:

    这样的东西应该作为一个起点,虽然你想充实一点以使其独立于平台等。

    (defun append-path-component (path new-part)
      (if (string-match ".*/$" path)
        (concat path new-part)
        (concat path "/" new-part)))
    

    像往常一样,可能有一些 elisp 已经做到了这一点,我只是不知道。

    【讨论】:

    • 谢谢。另外,我正在寻找那些可能存在的内置功能。
    • 这是一个可移植性失败。您不必在 lisp 代码中单独键入路径。
    • event_jr: directory-sep-char 早已过时,在 Emacs 24 中已完全删除。旧的文档字符串说“该值始终为 ?/。不要使用此变量,只需使用 @987654324 @。”
    【解决方案4】:

    除非您真的很在意将相对文件名保持为相对,否则最好避免使用 concat 并改用 expand-file-name

    【讨论】:

    • 能否举个例子说明两者的区别?
    【解决方案5】:
    (defun* tofilename (directorylist &optional (filename nil))
      "concatenate directory names into a path, with an optional file name as last part"
      (concat
       (mapconcat 'directory-file-name directorylist "/")
       "/"
       filename))
    
    
    (tofilename '("~/" "Temp/") "temp.txt")
    ;; => "~/Temp/temp.txt"
    
    (tofilename '("~/" "Temp/"))
    ;; => "~/Temp/"
    
    (tofilename '("~/" "Temp/" "test"))
    ;; => "~/Temp/temp/"
    

    【讨论】:

      【解决方案6】:

      如果您处理文件操作、连接和拆分文件路径、检查空目录等,我强烈建议您安装现代文件操作库f.el。您将在一个命名空间下拥有大量文件和文件路径操作函数,并且永远不会重新发明轮子。

      你需要的函数是f-join,它将路径的一部分连接起来,只在需要的地方添加斜杠。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-24
        • 2015-10-26
        • 1970-01-01
        • 2021-02-02
        相关资源
        最近更新 更多