如何使用 LUA 将绝对路径转换为相对路径?

我有两个绝对文件路径(AB)。我想将A转换为相对于B的路径。我该如何使用Lua脚本实现?

点赞
用户41655
用户41655

一个实现这个算法的方法是:

  1. 将两个路径转换为规范形式(即从文件系统根目录开始,没有尾随斜线、没有双斜线等)。
  2. 从两个路径中删除它们的公共前缀。(例如,从 A="/a/b/c/d.txt" B="/a/b/e/f.txt" 转换为 A="c/d.txt" B="e/f.txt"
  3. 将剩余的路径通过路径分隔符分割。(因此你将得到 A={"c", "d.txt"} B={"e", "f.txt"}
  4. 如果原始路径 B 指向一个普通文件,则删除 B 的最后一个元素。如果它指向一个目录,则保留不变。(对于我们的示例,你将得到 B={"e"}
  5. 对于 B 中剩余的每个项,在 A 的开头插入 ..。(结果为 A={"..", "c", "d.txt"}
  6. 使用路径分隔符将 A 的内容连接起来以获得最终结果:"../c/d.txt"

这是一个非常粗糙的实现,可以在没有任何库的情况下工作。它不处理任何边界情况,例如 fromto 相同,或者一个是另一个的前缀。(我指的是函数在这些情况下肯定会出问题,因为mismatch 将等于 0。)这主要是因为我很懒;也因为代码已经变得有点长了,这会进一步损害可读性。

-- to 和 from 必须在此时以规范绝对形式表示
to = "/a/b/c/d.txt"
from = "/a/b/e/f.txt"

min_len = math.min(to:len(), from:len())
mismatch = 0
print(min_len)

for i = 1, min_len do
    if to:sub(i, i) ~= from:sub(i, i) then
        mismatch = i
        break
    end
end

-- 处理边界情况

-- a 和 b 的不同部分
to_diff = to:sub(mismatch)
from_diff = from:sub(mismatch)

from_file = io.open(from)
from_is_dir = false
if (from_file) then
    -- 检查 from 是否是目录
    result, err_msg, err_no = from_file:read(0)
    if (err_no == 21) then -- EISDIR - `from` 是目录

end

result = ""
for slash in from_diff:gmatch("/") do
    result = result .. "../"
end
if from_is_dir then
    result = result .. "../"
end
result = result .. to_diff

print(result) --> ../c/d.txt
2012-11-05 01:13:48
用户204011
用户204011

使用 Penlight 库中的 pl.path.relpath 函数(文档 / 源码)。

2012-11-05 17:27:15
用户1534182
用户1534182

对于一般的 Lua 用户并不适用,但对于 neovim 用户,有一个有用的 plenary.nvim 实用程序可以用来实现:

local Path = require "plenary.path"
local abspath = "/a/b/c"
local cwd = "/a/"

local relpath = Path:new(abspath):make_relative(cwd)
relpath  -- "b/c"
2022-10-28 22:41:28