如何在Python中将dos路径拆分为其组件

时间:2010-07-02 15:41:57

标签: python

我有一个表示dos路径的字符串变量,例如:

var = "d:\stuff\morestuff\furtherdown\THEFILE.txt"

我想将此字符串拆分为:

[ "d", "stuff", "morestuff", "furtherdown", "THEFILE.txt" ]

我尝试过使用split()replace(),但他们要么只处理第一个反斜杠,要么在字符串中插入十六进制数字。

我需要以某种方式将此字符串变量转换为原始字符串,以便我可以解析它。

最好的方法是什么?

我还应该补充一点var的内容,即我尝试解析的路径,实际上是命令行查询的返回值。这不是我自己生成的路径数据。它存储在一个文件中,命令行工具不会逃避反斜杠。

23 个答案:

答案 0 :(得分:220)

我愿意

import os
path = os.path.normpath(path)
path.split(os.sep)

首先将路径字符串规范化为OS的正确字符串。然后os.sep必须安全地用作字符串函数拆分中的分隔符。

答案 1 :(得分:139)

我一直被人们写下自己的路径摆弄功能并弄错了。空格,斜线,反斜线,冒号 - 混淆的可能性并非无穷无尽,但无论如何都很容易犯错误。所以我是使用os.path的坚持者,并在此基础上推荐它。

(然而,走向美德的道路并不是最容易采取的道路,很多人在发现这种道路时,很容易直接走向诅咒。他们直到有一天一切都会崩溃,他们才会意识到 - 或者,更有可能的是,其他人 - 必须解决为什么一切都出错了,事实证明有人制作了混合斜杠和反斜杠的文件名 - 而且有人建议答案是“不要这样做”不要成为这些人中的任何一个。除了混合斜杠和反斜杠的人之外 - 如果你愿意,你可以成为他们。)

您可以像这样获取驱动器和路径+文件:

drive, path_and_file = os.path.splitdrive(path)

获取路径和文件:

path, file = os.path.split(path_and_file)

获取单个文件夹名称并不是特别方便,但它是一种诚实的中等不适,增加了以后找到实际效果良好的乐趣:

folders = []
while 1:
    path, folder = os.path.split(path)

    if folder != "":
        folders.append(folder)
    else:
        if path != "":
            folders.append(path)

        break

folders.reverse()

(如果路径最初是绝对路径,则会在"\"的开头弹出folders。如果您不想要,可能会丢失一些代码。)

答案 2 :(得分:72)

你可以简单地使用最Pythonic方法(恕我直言):

import os

your_path = r"d:\stuff\morestuff\furtherdown\THEFILE.txt"
path_list = your_path.split(os.sep)
print path_list

哪个会给你:

['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

此处的线索是使用os.sep代替'\\''/',因为这会使系统无关。

要从驱动器号中删除冒号(虽然我没有看到您为什么要这样做的原因),但您可以写:

path_list[0] = path_list[0][0]

答案 3 :(得分:41)

在Python> = 3.4中,这变得更加简单。您现在可以使用pathlib.Path.parts获取路径的所有部分。

示例:

>>> from pathlib import Path
>>> Path('C:/path/to/file.txt').parts
('C:\\', 'path', 'to', 'file.txt')
>>> Path(r'C:\path\to\file.txt').parts
('C:\\', 'path', 'to', 'file.txt')

在Windows 3的Windows安装中,这将假设您正在使用Windows路径,而在* nix上,它将假定您正在使用posix路径。这通常是您想要的,但如果不是,您可以根据需要使用课程pathlib.PurePosixPathpathlib.PureWindowsPath

>>> from pathlib import PurePosixPath, PureWindowsPath
>>> PurePosixPath('/path/to/file.txt').parts
('/', 'path', 'to', 'file.txt')
>>> PureWindowsPath(r'C:\path\to\file.txt').parts
('C:\\', 'path', 'to', 'file.txt')
>>> PureWindowsPath(r'\\host\share\path\to\file.txt').parts
('\\\\host\\share\\', 'path', 'to', 'file.txt')

编辑: 还有一个可以使用python 2的后端:pathlib2

答案 4 :(得分:11)

这里的问题首先从你如何创建字符串开始。

a = "d:\stuff\morestuff\furtherdown\THEFILE.txt"

通过这种方式,Python正在尝试这些特例:\s\m\f\T。在您的情况下,\f被视为换页(0x0C),而其他反斜杠被正确处理。你需要做的是其中之一:

b = "d:\\stuff\\morestuff\\furtherdown\\THEFILE.txt"      # doubled backslashes
c = r"d:\stuff\morestuff\furtherdown\THEFILE.txt"         # raw string, no doubling necessary

然后,一旦你拆开其中任何一个,你就会得到你想要的结果。

答案 5 :(得分:9)

有关更简洁的解决方案,请考虑以下事项:

def split_path(p):
    a,b = os.path.split(p)
    return (split_path(a) if len(a) and len(b) else []) + [b]

答案 6 :(得分:4)

我实际上无法真正回答这个问题(因为我来到这里希望自己找到一个),但对我来说,不同方法的数量以及所提到的所有警告都是Python的os.path模块的最可靠指标迫切需要这个作为内置功能。<​​/ p>

答案 7 :(得分:3)

它对我有用:

>>> a=r"d:\stuff\morestuff\furtherdown\THEFILE.txt"
>>> a.split("\\")
['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

当然,您可能还需要从第一个组件中删除冒号,但保留它可以重新组装路径。

r修饰符将字符串文字标记为“原始”;注意嵌入式反斜杠不会加倍。

答案 8 :(得分:1)

假设您有一个包含内容的文件filedata.txt

d:\stuff\morestuff\furtherdown\THEFILE.txt
d:\otherstuff\something\otherfile.txt

您可以阅读和拆分文件路径:

>>> for i in open("filedata.txt").readlines():
...     print i.strip().split("\\")
... 
['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']
['d:', 'otherstuff', 'something', 'otherfile.txt']

答案 9 :(得分:1)

关于约mypath.split("\\")的内容最好表达为mypath.split(os.pathsep)pathsep是您的特定平台的路径分隔符(例如,Windows的\,Unix的/等),Python构建知道要使用哪个。如果您使用pathsep,那么您的代码将与平台无关。

答案 10 :(得分:1)

re.split()可以比string.split()

多一点
import re    
var = "d:\stuff\morestuff\furtherdown\THEFILE.txt"
re.split( r'[\\/]', var )
['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

如果您还想支持Linux和Mac路径,只需添加过滤器(无,结果),这样就会从split()中删除不需要的'',因为它们的路径以'/'或'//'开头。例如'// mount / ...'或'/ var / tmp /'

import re    
var = "/var/stuff/morestuff/furtherdown/THEFILE.txt"
result = re.split( r'[\\/]', var )
filter( None, result )
['var', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

答案 11 :(得分:1)

功能方式,使用生成器

def split(path):
    (drive, head) = os.path.splitdrive(path)
    while (head != os.sep):
        (head, tail) = os.path.split(head)
        yield tail

行动中:

>>> print([x for x in split(os.path.normpath('/path/to/filename'))])
['filename', 'to', 'path']

答案 12 :(得分:1)

您可以递归os.path.split字符串

import os
def parts(path):
    p,f = os.path.split(path)
    return parts(p) + [f] if f else [p]

针对某些路径字符串对此进行测试,并使用os.path.join

重新组合路径
>>> for path in [
...         r'd:\stuff\morestuff\furtherdown\THEFILE.txt',
...         '/path/to/file.txt',
...         'relative/path/to/file.txt',
...         r'C:\path\to\file.txt',
...         r'\\host\share\path\to\file.txt',
...     ]:
...     print parts(path), os.path.join(*parts(path))
... 
['d:\\', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt'] d:\stuff\morestuff\furtherdown\THEFILE.txt
['/', 'path', 'to', 'file.txt'] /path\to\file.txt
['', 'relative', 'path', 'to', 'file.txt'] relative\path\to\file.txt
['C:\\', 'path', 'to', 'file.txt'] C:\path\to\file.txt
['\\\\', 'host', 'share', 'path', 'to', 'file.txt'] \\host\share\path\to\file.txt

列表的第一个元素可能需要区别对待,具体取决于您要如何处理驱动器号,UNC路径以及绝对路径和相对路径。将最后一个[p]更改为[os.path.splitdrive(p)]会将驱动器号和目录根分成一个元组来强制解决问题。

import os
def parts(path):
    p,f = os.path.split(path)
    return parts(p) + [f] if f else [os.path.splitdrive(p)]

[('d:', '\\'), 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']
[('', '/'), 'path', 'to', 'file.txt']
[('', ''), 'relative', 'path', 'to', 'file.txt']
[('C:', '\\'), 'path', 'to', 'file.txt']
[('', '\\\\'), 'host', 'share', 'path', 'to', 'file.txt']

编辑:我已经意识到这个答案与that given aboveuser1556435非常相似。由于对路径的驱动器组件的处理不同,我还是留下了我的答案。

答案 13 :(得分:0)

from os import path as os_path

然后

def split_path_iter(string, lst):
    head, tail = os_path.split(string)
    if head == '':
        return [string] + lst
    else:
        return split_path_iter(head, [tail] + lst)

def split_path(string):
    return split_path_iter(string, [])

或者,受上述答案启发(更优雅):

def split_path(string):
    head, tail = os_path.split(string)
    if head == '':
        return [string]
    else:
        return split_path(head) + [tail]

答案 14 :(得分:0)

太可惜了! python os.path 没有类似 os.path.splitall 的东西

无论如何,这对我有用,信用:https://www.oreilly.com/library/view/python-cookbook/0596001673/ch04s16.html

import os

a = '/media//max/Data/'

def splitall(path):
    # https://www.oreilly.com/library/view/python-cookbook/0596001673/ch04s16.html
    allparts = []
    while 1:
        parts = os.path.split(path)
        if parts[0] == path:  # sentinel for absolute paths
            allparts.insert(0, parts[0])
            break
        elif parts[1] == path: # sentinel for relative paths
            allparts.insert(0, parts[1])
            break
        else:
            path = parts[0]
            allparts.insert(0, parts[1])
    return allparts

x = splitall(a)
print(x)

z = os.path.join(*x)
print(z)

输出:

['/', 'media', 'max', 'Data', '']
/media/max/Data/

答案 15 :(得分:0)

调整了@Mike Robins的解决方案,避免在开始时使用空路径元素:

def parts(path):
    p,f = os.path.split(os.path.normpath(path))
    return parts(p) + [f] if f and p else [p] if p else []

os.path.normpath()实际上只需要一次,可以在递归的单独输入函数中完成。

答案 16 :(得分:0)

非常简单的方法:

var.replace('\\', '/').split('/')

答案 17 :(得分:0)

下面的代码行可以处理:

  1. C:/ path / path
  2. C://路径//路径
  3. C:\ path \ path
  4. C:\ path \ path

path = re.split(r'[/// \]',path)

答案 18 :(得分:0)

我真的不确定这是否完全回答了这个问题,但是我很乐意写这个小函数来保持堆栈,坚持基于os.path的操作,并返回列表/堆栈的项目。 / p>

  9 def components(path):
 10     ret = []
 11     while len(path) > 0:
 12         path, crust = split(path)
 13         ret.insert(0, crust)
 14
 15     return ret
 16

答案 19 :(得分:0)

我使用以下内容,因为它使用os.path.basename函数,它不会向返回的列表添加任何斜杠。它也适用于任何平台的斜杠:即窗口的\\或unix的/。此外,它不会添加Windows用于服务器路径的\\\\:)

def SplitPath( split_path ):
    pathSplit_lst   = []
    while os.path.basename(split_path):
        pathSplit_lst.append( os.path.basename(split_path) )
        split_path = os.path.dirname(split_path)
    pathSplit_lst.reverse()
    return pathSplit_lst

对于'\\\\ server \\ folder1 \\ folder2 \\ folder3 \\ folder4'

你得到了

[ '服务器', '文件夹1', '文件夹2', 'folder3', 'folder4']

答案 20 :(得分:0)

就像其他人解释的那样 - 你的问题源于使用\,它是字符串文字/常量中的转义字符。 OTOH,如果你有来自另一个源的文件路径字符串(从文件,控制台读取或由os函数返回) - 在'\\'或r'\'上没有问题分裂。

就像其他人建议的那样,如果你想在程序文字中使用\,你必须复制它\\或者整个文字必须以r作为前缀,就像所以r'lite\ral'r"lite\ral"以避免解析器将\r转换为CR(回车)字符。

还有一种方法 - 只是不要在代码中使用反斜杠\路径名!自上个世纪以来,Windows识别并使用正斜杠作为目录分隔符/的路径名正常工作!不知怎的,没有多少人知道......但是它有效:

>>> var = "d:/stuff/morestuff/furtherdown/THEFILE.txt"
>>> var.split('/')
['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

顺便说一句,这将使您的代码在Unix,Windows和Mac上运行...因为所有这些代码都使用/作为目录分隔符...即使您不想使用预定义的常量模块os

答案 21 :(得分:-1)

一个递归的乐趣。

这不是最优雅的答案,但应该可以在任何地方使用

import os

def split_path(path):
    head = os.path.dirname(path)
    tail = os.path.basename(path)
    if head == os.path.dirname(head):
        return [tail]
    return split_path(head) + [tail]

答案 22 :(得分:-1)

使用ntpath.split()