如何在Python中以与操作系统无关的方式归一化/压缩路径或URL?

5 投票
3 回答
7033 浏览
提问于 2025-04-15 18:26

我试着用 os.normpath 来把 http://example.com/a/b/c/../ 转换成 http://example.com/a/b/,但是在Windows上不行,因为它把斜杠变成了反斜杠。

3 个回答

2

这段话的意思是,"os"模块里有一个叫做"os.path"的部分,它实际上是由"posixpath"或"ntpath"这两个模块组成的。在你的情况下,明确使用的是"posixpath"。

   >>> import posixpath
    >>> posixpath.normpath("/a/b/../c")
    '/a/c'
    >>> 
8

既然 urljoinposixpath.normpath 都不能正确处理这个问题urljoin 要求你必须和某个东西连接,而且对绝对路径或过多的 .. 处理得不太好。posixpath.normpath 会把多个斜杠合并,并去掉末尾的斜杠,这些都是网址不应该做的事情。


下面这个函数可以完全解析网址,正确处理 ...,符合 RFC 3986 的标准。

try:
    # Python 3
    from urllib.parse import urlsplit, urlunsplit
except ImportError:
    # Python 2
    from urlparse import urlsplit, urlunsplit

def resolve_url(url):
    parts = list(urlsplit(url))
    segments = parts[2].split('/')
    segments = [segment + '/' for segment in segments[:-1]] + [segments[-1]]
    resolved = []
    for segment in segments:
        if segment in ('../', '..'):
            if resolved[1:]:
                resolved.pop()
        elif segment not in ('./', '.'):
            resolved.append(segment)
    parts[2] = ''.join(resolved)
    return urlunsplit(parts)

你可以像下面这样在一个完整的网址上调用它。

>>> resolve_url("http://example.com/dir/../../thing/.")
'http://example.com/thing/'

想了解更多关于解析网址时需要考虑的事项,可以查看 我之前写的一个类似的回答

8

下面是怎么做的

>>> import urlparse
>>> urlparse.urljoin("ftp://domain.com/a/b/c/d/", "../..")
'ftp://domain.com/a/b/'
>>> urlparse.urljoin("ftp://domain.com/a/b/c/d/e.txt", "../..")
'ftp://domain.com/a/b/'    

记住,urljoin 会把最后一个 / 之前的部分都当作路径或目录,后面的是文件名(如果有的话)。

另外,第二个参数前面不要加 /,否则你得到的结果可能不是你想要的。

os.path 模块是和操作系统有关的,但如果你只是在处理文件路径(不是网址),可以使用 posixpathnormpath

撰写回答