Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何规避Python的谬误';s os.path.commonprefix?_Python_Path_Prefix - Fatal编程技术网

如何规避Python的谬误';s os.path.commonprefix?

如何规避Python的谬误';s os.path.commonprefix?,python,path,prefix,Python,Path,Prefix,我的问题是找到给定文件集的公共路径前缀 从字面上说,我希望“os.path.commonprefix”能做到这一点。不幸的是,commonprefix位于path中这一事实相当误导,因为它实际上会搜索字符串前缀 我的问题是,如何解决路径的问题?该问题已在中简要提及,但仅作为旁注,拟议的解决方案(在commonprefix的输入中添加斜杠)imho存在问题,因为它将失败,例如: os.path.commonprefix(['/usr/var1/log/', '/usr/var2/log/']) #

我的问题是找到给定文件集的公共路径前缀

从字面上说,我希望“os.path.commonprefix”能做到这一点。不幸的是,
commonprefix
位于
path
中这一事实相当误导,因为它实际上会搜索字符串前缀

我的问题是,如何解决路径的问题?该问题已在中简要提及,但仅作为旁注,拟议的解决方案(在commonprefix的输入中添加斜杠)imho存在问题,因为它将失败,例如:

os.path.commonprefix(['/usr/var1/log/', '/usr/var2/log/'])
# returns /usr/var but it should be /usr

为了防止其他人落入相同的陷阱,可能值得在另一个问题中讨论此问题:是否有一个简单/可移植的解决方案可以解决此问题,而不依赖于对文件系统的恶意检查(即,访问commonprefix的结果并检查它是否是目录,如果不是,则返回结果的
os.path.dirname

假设您想要公共目录路径,一种方法是:

  • 仅使用目录路径作为输入。如果输入值是文件名,请调用
    os.path.dirname(filename)
    获取其目录路径
  • “规范化”所有路径,使它们相对于同一事物,并且不包含双分隔符。最简单的方法是调用
    os.path.abspath()
    以获取相对于根的路径。(您可能还需要使用
    os.path.realpath()
    来删除符号链接。)
  • 在所有规范化目录路径的末尾添加最后一个分隔符(可通过
    os.path.sep
    os.sep
    移动找到)
  • os.path.commonprefix()
    的结果调用
    os.path.dirname()
  • 在代码中(不删除符号链接):


    不久前,我遇到了这样一个问题,
    os.path.commonprefix
    是字符串前缀,而不是预期的路径前缀。因此我写了以下内容:

    def commonprefix(l):
        # this unlike the os.path.commonprefix version
        # always returns path prefixes as it compares
        # path component wise
        cp = []
        ls = [p.split('/') for p in l]
        ml = min( len(p) for p in ls )
    
        for i in range(ml):
    
            s = set( p[i] for p in ls )         
            if len(s) != 1:
                break
    
            cp.append(s.pop())
    
        return '/'.join(cp)
    

    通过将
    '/'
    替换为
    os.path.sep

    可以使它更具可移植性。一种可靠的方法是将路径拆分为各个组件,然后找到组件列表中最长的公共前缀

    这是一个跨平台的实现,可以很容易地推广到两条以上的路径:

    import os.path
    import itertools
    
    def components(path):
        '''
        Returns the individual components of the given file path
        string (for the local operating system).
    
        The returned components, when joined with os.path.join(), point to
        the same location as the original path.
        '''
        components = []
        # The loop guarantees that the returned components can be
        # os.path.joined with the path separator and point to the same
        # location:    
        while True:
            (new_path, tail) = os.path.split(path)  # Works on any platform
            components.append(tail)        
            if new_path == path:  # Root (including drive, on Windows) reached
                break
            path = new_path
        components.append(new_path)
    
        components.reverse()  # First component first 
        return components
    
    def longest_prefix(iter0, iter1):
        '''
        Returns the longest common prefix of the given two iterables.
        '''
        longest_prefix = []
        for (elmt0, elmt1) in itertools.izip(iter0, iter1):
            if elmt0 != elmt1:
                break
            longest_prefix.append(elmt0)
        return longest_prefix
    
    def common_prefix_path(path0, path1):
        return os.path.join(*longest_prefix(components(path0), components(path1)))
    
    # For Unix:
    assert common_prefix_path('/', '/usr') == '/'
    assert common_prefix_path('/usr/var1/log/', '/usr/var2/log/') == '/usr'
    assert common_prefix_path('/usr/var/log1/', '/usr/var/log2/') == '/usr/var'
    assert common_prefix_path('/usr/var/log', '/usr/var/log2') == '/usr/var'
    assert common_prefix_path('/usr/var/log', '/usr/var/log') == '/usr/var/log'
    # Only for Windows:
    # assert common_prefix_path(r'C:\Programs\Me', r'C:\Programs') == r'C:\Programs'
    

    我制作了一个小型python包
    commonpath
    ,用于从列表中查找公共路径


    最近的Python版本似乎已经纠正了这个问题。3.5版的新功能是返回公共路径而不是公共字符串前缀的函数。

    当我考虑这个想法时,我最初拒绝了它,因为我认为在处理相对路径时,添加斜杠是一个问题,比如空白的f当前目录中的文件名。但是,当将所有路径包装到
    os.path.abspath
    中时,即使是相对路径和绝对路径的混合也不会有问题,对吗?@bluenote10 right,
    abspath
    而不是
    normpath
    将处理相对路径。不确定是否为空文件名,因为这与dupl不明确icated路径分隔符。有人允许零长度的文件名吗?哦,我不是指空文件名,只是
    “aSimpleFileName”
    。应该提到的是,这完全取决于
    路径是文件路径还是目录路径(这必须是一种惯例,以防我们想要避免文件系统访问)在我的问题中,
    路径实际上是文件而不是目录。我认为在这种情况下,正确的顺序是:(a)转换为abspath以处理相对/绝对路径的混合;(b)应用dirname将其转换为正确的目录。从这一点上,我认为我们可以安全地应用您的解决方案。哦,现在我明白了,这一点很好。您需要提前知道您的字符串是文件还是目录路径。我以为我已经解决了这个问题,但我只是假设了目录。我接受了这个答案,因为它在主目录下相当健壮非常简洁。有趣的是,与基于
    os.path.compomatiprefix
    (参见Dan Getz的回答)的解决方案相比,组件级比较并不取决于输入路径是文件名还是目录名(仅仅因为文件名是唯一的组件)。对于更稳健的方法,我推荐EOL的答案,并进一步了解
    os.path.commonprefix
    Dan Getz的问题。Dan Getz的答案非常有启发性。谢谢大家!这给出了一个文件名或目录名的合理答案,但在一般情况下,您无法确定函数的结果是文件还是目录命名而不做更多的工作(例如通过控制输入)。此外,我相信这会返回与
    os.path.dirname(os.path.commonprefix([p+'/'表示l中的p])完全相同的结果
    ?@DanGetz显然不一样。我只是在windows上用
    os.path.sep
    替换了它,@DanD提供的代码得到了正确的公共路径,而您的代码段返回
    None
    。@这是什么输入导致的?我不知道
    dirname
    可以返回
    None
    @DanGetz I must在某个地方把它搞砸了。我刚刚在一个新的环境中再次尝试了它,它成功了。我的坏。相关问题:。管道中有一个补丁。谢谢!这是切换到python 3的另一个原因——很高兴我去年终于这么做了。
    import os.path
    import itertools
    
    def components(path):
        '''
        Returns the individual components of the given file path
        string (for the local operating system).
    
        The returned components, when joined with os.path.join(), point to
        the same location as the original path.
        '''
        components = []
        # The loop guarantees that the returned components can be
        # os.path.joined with the path separator and point to the same
        # location:    
        while True:
            (new_path, tail) = os.path.split(path)  # Works on any platform
            components.append(tail)        
            if new_path == path:  # Root (including drive, on Windows) reached
                break
            path = new_path
        components.append(new_path)
    
        components.reverse()  # First component first 
        return components
    
    def longest_prefix(iter0, iter1):
        '''
        Returns the longest common prefix of the given two iterables.
        '''
        longest_prefix = []
        for (elmt0, elmt1) in itertools.izip(iter0, iter1):
            if elmt0 != elmt1:
                break
            longest_prefix.append(elmt0)
        return longest_prefix
    
    def common_prefix_path(path0, path1):
        return os.path.join(*longest_prefix(components(path0), components(path1)))
    
    # For Unix:
    assert common_prefix_path('/', '/usr') == '/'
    assert common_prefix_path('/usr/var1/log/', '/usr/var2/log/') == '/usr'
    assert common_prefix_path('/usr/var/log1/', '/usr/var/log2/') == '/usr/var'
    assert common_prefix_path('/usr/var/log', '/usr/var/log2') == '/usr/var'
    assert common_prefix_path('/usr/var/log', '/usr/var/log') == '/usr/var/log'
    # Only for Windows:
    # assert common_prefix_path(r'C:\Programs\Me', r'C:\Programs') == r'C:\Programs'