如何在Python中以与操作系统无关的方式规范化/折叠路径或URL?

5

我试图使用os.normpathhttp://example.com/a/b/c/../转换为http://example.com/a/b/,但在Windows上它不起作用,因为它会将斜杠转换为反斜杠。

3个回答

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模块依赖于平台,但对于仅使用斜杠而非URL的文件路径,您可以使用posixpath、normpath


相反地:如果第二个参数有一个前导的 /,它将返回 ftp://domain.com/../..。进行修正。 - Josh Lee

7
urljoinposixpath.normpath都不能正确地完成工作。 urljoin强制你连接某些东西,并且无法正确处理绝对路径或过多的..posixpath.normpath折叠多个斜杠并删除尾部斜杠,这些都是URL不应该做的事情。
下面的函数完全解析URL,以正确的方式处理 . .. ,符合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)

您可以按照以下方式在完整的URL上调用它。
>>> resolve_url("http://example.com/dir/../../thing/.")
'http://example.com/thing/'

关于解析URL时需要考虑的问题,更多信息请参见我之前在该主题上撰写的类似答案


2

从os模块采用“ - os.path是模块posixpath或ntpath之一”,在您的情况下明确使用posixpath。

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

3
posixpath.normpath会做一些不太有用的事情,例如删除尾部斜杠并允许双斜杠开头。还会将空路径替换为. - Tom Viner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接