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


152

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

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

我想将此字符串拆分为:

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

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

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

最好的方法是什么?

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


6
查看这些答案时,请记住这os.path.split对您不起作用,因为您没有正确地转义该字符串。
杰德·史密斯

您需要转义字符串或使用rawstring:r"d:\stuff\morestuff\furtherdown\THEFILE.txt"来防止诸如\s被误解之类的事情。
smci

Answers:


163

人们一直在编写自己的路径摆弄功能并弄错了它,这使我倍感痛苦。空格,斜杠,反斜杠,冒号-混乱的可能性并非无止境,但无论如何还是容易犯错误。因此,我非常喜欢使用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则会在此路径的开头弹出a 。如果不希望这样做,可能会丢失一些代码。)


@brone-我更喜欢使用此解决方案,而不必担心转义反斜杠。谢谢!
BeeBand 2010年

1
我很乐意被证明是错误的,但是在我看来,如果使用诸如“ C:\ usr \ rs0 \ my0 \ in111102.log”之类的路径,则建议的解决方案不起作用(除非初始输入是原始字符串) )?
shearichard 2011年

1
如果它仅在OSX中包含目录(例如“ / path / to / my / folder /”),则看起来无法正确分割路径,以实现将这两行添加到开头:if path.endswith("/"):path = path[:-1]
凯文·伦敦,

1
我更喜欢使用@Tompa解决方案
jaycode

1
我同意jaycode东巴解决方案规范的做法,应该已经接受的答案。这种过于复杂,效率低下且容易出错的替代方案无法在生产代码上传递要求。有没有合理的理由去尝试(...和失败,当然)反复地解析路径名分开时,简单的字符串分割,只有一个成功的一行代码。
Cecil Curry 2015年

287

我会做

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

首先,将路径字符串标准化为适合操作系统的字符串。然后os.sep必须安全地用作字符串函数分割中的定界符。


25
一个真实的答案:它已经出现了。当然,规范的解决方案是最简单的。看哪!因为它优雅而时尚,并且没有任何难以承受的边缘情况。
Cecil Curry 2015年

20
作为单线工作,os.path.normpath(a_path).split(os.path.sep)
Daniel Farrell

2
这似乎不适用于path = root。在这种情况下,path.split的结果为['','']。实际上,通常,此split()解决方案为最左边的目录提供了空字符串名称(可以用适当的斜杠代替)。核心问题是根目录的名称是单个斜杠(根据操作系统的不同,是正斜杠还是后斜杠),而在路径的其他地方则是分隔符
gwideman '16

2
那么,使用lstrip会更好吗?os.path.normpath(path).lstrip(os.path.sep).split(os.path.sep)
维达尔

1
@ user60561那是因为在Linux上,反斜杠是文件名中允许使用的字符,而在Windows上则不是正斜杠。这就是在Windows normpath上将正斜杠识别为分隔符的原因。在Linux上,normpath仅假设您有一个目录称为,\1\2并且其中有一个文件或目录3
Vojislav Stojkovic '18

81

您可以简单地使用最Python化的方法(IMHO):

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]

22
这有效some times。其他时间(至少在Windows上),您会找到类似的路径folder\folder2\folder3/file.txt。最好先规范化(os.path.normpath)路径,然后将其拆分。
vikki 2014年

7
这个答案几乎就在那里。正如vikki所建议的那样,在字符串拆分之前未能对路径名进行规范化在常见的边缘情况(例如/foo//bar)上注定要失败。有关更可靠的解决方案,请参见Tompa答案
Cecil Curry 2015年

62

在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安装的Python 3上,这将假定您正在使用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


3
Path.parts是我一直想要的,但是直到今天我还不知道它的存在。
JamEnergy

为什么没有将它包装在一个不错的本地python函数周围?
Eduardo Pignatelli,

2
这就是答案!
nayriz

11

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

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

使用这种方式时,巨蟒试图特殊情况下,这些:\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

然后,将其中任何一个拆分后,您将获得所需的结果。


@W。Craig Trader-谢谢,但是这不是我自己生成的路径-它是从另一个程序返回给我的,我必须将此数据存储在变量中。我不确定如何将存储在变量中的数据转换为“原始文本”。
BeeBand 2010年

没有所谓的“原始文本”……这只是您在源代码中的表示方式。任一前置R“”的字符串,或使其通过.replace(“\\”,“/”)
马可马里亚尼

@BeeBand,您如何从其他程序获取数据?您是从文件,管道,套接字读取数据吗?如果是这样,那么您就不需要做任何花哨的事情了。将反斜杠加倍或使用原始字符串的唯一原因是将字符串常量放入Python代码中。另一方面,如果另一个程序正在生成双反斜杠,那么您希望在拆分路径之前将其清除。
Craig Trader

@W。Craig Trader-我正在从一个文件读取文件,该文件是由另一个程序编写的。由于某种原因,我无法上班split()replace()上班-我一直在获取十六进制值。但是,您是对的,我认为我用原始的字符串想法在错误的树上吠叫-我认为我只是在split()错误地使用。因为我尝试使用了其中一些解决方案split(),所以它们现在对我有用。
BeeBand 2010年

10

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

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

这是我最喜欢的解决方案。非常好。
Will Moore

1
如果路径以结尾,则此方法无效/。此外,如果您的路径以/
Sorig

4

我实际上无法对此做出真正的回答(因为我来这里只是为了找到一个我自己),但是对我来说,不同方法的数量以及所提到的所有警告是最确定的指标,表明Python的os.path模块迫切需要这一点。作为内置功能。


4

具有生成器的功能方式。

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']

3

这个对我有用:

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

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

r修改标记字符串文字为“原始”; 注意嵌入的反斜杠如何不加倍。


@unwind- r字符串前面的,是什么意思?
BeeBand

2
r表示原始字符串-它会自动转义\ 字符。在执行路径操作时使用它很有用。
韦恩·沃纳

1
@BeeBand:您不需要在意;r“”只是在代码的编译/解析过程中重要的事情,它一旦解析就不会成为字符串的属性。它只是意味着“这是一个字符串文字,但不要将任何反斜杠解释为除反斜杠之外还有其他含义”。
放松

3
我认为提到您可能会有所帮助,而使用a.split(os.sep)而不是硬编码会使其更加模棱两可吗?
蒂姆·麦克吉尔顿

4
我不得不downvote你缺少一个解释的机会os.path.splitos.pathsep,同时考虑那些比你所写的内容更便携。现在对OP可能无关紧要,但是当他编写需要移动平台的东西时,这将无关紧要。
杰德·史密斯

3

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


1
或者os.path.split。您需要注意os.pathsep,因为它:在OS X中的我的Python版本上(并os.path.split正确处理/)。
杰德·史密斯

4
你的意思os.sep不是os.pathsep。遵循os.sep文档中的知识:请注意,仅了解这一点不足以解析或连接路径名-使用os.path.split()和os.path.join()。
乔恩·埃里克

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路径,只需添加filter(None,result),由于它的路径以'/'或'//'开头,因此它将从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']

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']

编辑:我已经意识到,这个答案是非常相似的,上面给出user1556435。我留下我的答案,因为路径的驱动器组件的处理方式不同。


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上运行...因为它们全部都/用作目录分隔符...即使您不想使用module的预定义常量os


不幸的是,数据是从我从python脚本运行的另一个程序返回给我的。我对使用'\'还是'/'没有任何控制权-它是由第三方程序确定的(可能基于平台)。
BeeBand 2010年

@BeeBand:啊,那么当您在程序中提供字符串作为原义时,就不会遇到测试期间遇到的问题。或者,您也可以在收到路径后进行以下恶意破解:var = var.replace('\\','/')-用/替换\,然后仅使用正斜杠:)
Nas Banov 2010年

那确实是一个邪恶的hack:o)
BeeBand

@BeeBand:这就是为什么我警告。当我说某件事是邪恶的时,我并不一定意味着它永远不应该被使用-但是人们应该非常清楚他们为什么使用它并警惕意想不到的后果。在这种情况下,非常不可能的结果是,如果在Unix文件系统上使用``在文件或目录名中使用(这确实很困难,但是可能的话)–该代码将'中断'
Nas Banov,2010年

0

假设您有一个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']

这确实有效,谢谢!但是我选择了brone的解决方案,因为我不想担心转义反斜杠。
BeeBand 2010年

9
不是pythonic的,因为它依赖于文件系统。
jb。

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','文件夹3','文件夹4']


1
这并没有遵循将结果传递给os.path.join()原始字符串的不变性。我想说的是您的示例输入的正确输出是[r'\\','server','folder1','folder2','folder3','folder4']。即是什么os.path.split()
乔恩·埃里克

0

我实际上不确定这是否可以完全回答问题,但是我很开心地编写了这个小功能,该功能可以保持堆栈,坚持使用基于os.path的操作并返回项目的列表/堆栈。

  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

0

下面的代码行可以处理:

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

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


0

一种递归的乐趣。

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

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]

的确,抱歉。应该已经仔细阅读了问题……一条“ dos”之路。
DuGNu

-1

ntpath.split()


当我使用os.path.split()时,我得到(d:\\stuffmorestuff\x0curtherdown\thefile.mux
BeeBand 2010年

正如BeeBand所指出的那样,os.path.split()确实没有做所需的事情。
放松

抱歉,我只是意识到os.path仅取决于您的操作系统。ntpath将解析dos路径。
deft_code 2010年

即使使用ntpath,我仍然会得到d:\\stuff, morestuff\x0curtherdown\thefile.mux
BeeBand

2
@BeeBand:转义字符串时遇到问题。 '\x0c'是换页字符。创建换页符的方法是'\ f'。如果您确实需要文字字符串'\ f',则有两个选择:'\\f'r'\f'
deft_code 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.