如何在Python中将dospath拆分为其组件

我有一个stringvariables,代表一个DOSpath例如:

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

我想把这个string分成:

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

我已经尝试使用split()replace()但它们只处理第一个反斜杠,或者将hex数字插入到string中。

我需要将此stringvariables转换为原始string,以便我可以parsing它。

什么是最好的方法来做到这一点?

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

人们一直在写自己的path,摆弄function,弄错了一些东西。 空格,斜线,反斜线,冒号 – 混淆的可能性并不是无止境的,但错误很容易发生。 所以我是os.path的使用者,并在此基础上推荐它。

(但是,走向美德的道路并不是最容易被接受的道路,很多人在find这条道路时,都试图走上一条滑道,直到有一天,所有东西都碎了,而且 – ,更有可能的是,别人 – 必须弄清楚为什么一切都出错了,结果certificate有人制作了一个混合了斜杠和反斜杠的文件名 – 有人build议答案是“不要这样做”不是这些人中的任何人,除了那些混合了斜线和反斜线的人之外 – 如果你愿意的话,你可以成为他们)。

你可以得到像这样的驱动器和path+文件:

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

获取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() 

(如果path最初是绝对path的话,这会在folders开始处popup一个"\" ,如果你不想要的话,你可能会丢失一些代码。)

我会做

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

首先将pathstring标准化为操作系统的适当string。 然后os.sep在string函数split中作为分隔符必须是安全的。

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

 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] 

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

例:

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

在Python 3的Windows安装中,这将假定您正在使用Windowspath,并且在* nix上它将假定您正在使用posixpath。 这通常是你想要的,但如果不是,你可以根据需要使用类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

这里的问题从你如何创buildstring开始。

 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 

然后,一旦你分裂这些,你会得到你想要的结果。

对于更简洁的解决scheme,请考虑以下几点:

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

这个对我有用:

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

当然,你也可能需要从第一个组件中去掉冒号,但保留它可以重新组装path。

r修饰符将string文字标记为“raw”; 请注意embedded的反斜杠如何不加倍。

我实际上无法为这个问题提供一个真正的答案(因为我来这里希望自己find一个答案),但是对于我来说,不同的方法和提到的所有注意事项的数量是最可靠的指标,Python的os.path模块迫切需要这个作为一个内置函数。

假设你有一个带有内容的文件filedata.txt

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

您可以读取和分割文件path:

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

有关mypath.split("\\")可以更好地表示为mypath.split(os.pathsep)pathsep是你的特定平台的path分隔符(例如, \ for Windows, / for Unix等),并且Python构build知道使用哪一个。 如果你使用pathsep ,那么你的代码将是平台不可知的。

re.split()可以帮助多一点string.split()

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

如果您还想支持Linux和Macpath,只需添加filter(无,结果),因此它将从split()中移除不需要的“',因为它们的path以”/“或”//“开头。 例如'// 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'] 

function方式,带发电机

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

你可以recursion的os.path.split这个string

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

对一些pathstring进行testing,然后用os.path.join重新组装path

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

根据您想要处理驱动器号,UNCpath以及绝对path和相对path,列表中的第一个元素可能需要以不同的方式处理。 将最后一个[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 。 我把答案留给path的驱动组件的处理是不同的。

就像其他人解释的一样 – 你的问题源于使用\ ,它是string常量/常量中的转义字符。 OTOH,如果你从另一个源文件pathstring(从文件,控制台读取或由os函数返回) – 在\\或r \\上不会出现问题分裂。

就像其他人一样,如果你想在程序中使用\ ,你必须重复它\\或者整个字面量必须以r为前缀,就像r'lite\ral'r"lite\ral"避免parsing器将该\r转换为CR(回车)字符。

还有一种方法 – 只是不要在你的代码中使用反斜线\path名! 自从上个世纪以来,Windows能够识别和使用正斜杠作为目录分隔符的path名! 不知怎的,没有多less人知道..但它的工作原理:

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

顺便说一句,这将使你的代码工作在Unix,Windows和Mac …因为他们都使用/作为目录分隔符…即使你不想使用模块os预定义的常量。

我使用下面的,因为它使用os.path.basename函数它不会添加任何斜杠到返回的列表。 它也适用于任何平台的斜杠:即窗口的\\或unix的/。 而且,它不会添加Windows用于服务器path的\\\\ 🙂

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

我不确定这是否能够完全回答这个问题,但是我有一段时间写这个小函数来保持堆栈,坚持使用基于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 

使用ntpath.split()