关于python:从路径中提取文件名,无论os / path格式是什么

Extract file name from path, no matter what the os/path format

无论操作系统或路径格式如何,我都可以使用哪个python库从路径中提取文件名?

例如,我希望所有这些路径返回我c

1
2
3
4
5
6
7
a/b/c/
a/b/c
\a\b\c
\a\b\c\
a\b\c
a/b/../../a/b/c/
a/b/../../a/b/c

实际上,有一个函数可以返回您想要的

1
print(os.path.basename(your_path))


按照其他人的建议,使用os.path.splitos.path.basename在所有情况下都不起作用:如果您在Linux上运行脚本并尝试处理经典的Windows风格的路径,它将失败。

Windows路径可以使用反斜杠或正斜杠作为路径分隔符。因此,ntpath模块(在Windows上运行时相当于os.path)将适用于所有平台上的所有(1)条路径。

1
2
import ntpath
ntpath.basename("a/b/c")

当然,如果文件以斜杠结尾,则basename将为空,因此请使用自己的函数来处理它:

1
2
3
def path_leaf(path):
    head, tail = ntpath.split(path)
    return tail or ntpath.basename(head)

验证:

1
2
3
4
>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
...     '
a/b/../../a/b/c/', 'a/b/../../a/b/c']
>>> [path_leaf(path) for path in paths]
['
c', 'c', 'c', 'c', 'c', 'c', 'c']

(1)有一个警告:Linux文件名可能包含反斜杠。因此,在Linux上,r'a/b\c'总是指a文件夹中的文件b\c,而在Windows上,它总是指a文件夹的b子文件夹中的c文件。因此,当在路径中同时使用向前和向后斜杠时,您需要知道关联的平台才能正确地解释它。实际上,假设它是Windows路径通常是安全的,因为在Linux文件名中很少使用反斜杠,但是在编写代码时要记住这一点,这样就不会造成意外的安全漏洞。


O.P.P.分裂是你要找的功能吗

1
2
3
4
5
6
head, tail = os.path.split("/tmp/d/a.dat")

>>> print(tail)
a.dat
>>> print(head)
/tmp/d


1
2
3
import os
head, tail = os.path.split(p)
print tail

假设p是输入字符串,tail是您想要的。

详见python os module docs


在Python 3中

1
2
3
>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'


在您的示例中,您还需要从右侧去掉斜线以返回c

1
2
3
4
5
>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'

二级:

1
2
>>> os.path.filename(os.path.dirname(path))
'b'

更新:我认为lazyr提供了正确的答案。我的代码不适用于UNIX系统上类似Windows的路径和Windows系统上类似Unix的路径。


1
fname = str("C:\Windows\paint.exe").split('\')[-1:][0]

这将返回:paint.exe

change the sep value of the split function regarding your path or OS.


这适用于Linux和Windows以及标准库。

1
2
3
4
5
6
7
paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
         '
a/b/../../a/b/c/', 'a/b/../../a/b/c']

def path_leaf(path):
    return path.strip('
/').strip('\').split('/')[-1].split('\')[-1]

[path_leaf(path) for path in paths]

结果:

1
['c', 'c', 'c', 'c', 'c', 'c', 'c']

我从未见过双反斜杠路径,它们存在吗?python模块os的内置特性对这些功能无效。所有其他工作,也包括你对os.path.normpath()的警告:

1
2
3
4
paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
...     '
a/b/../../a/b/c/', 'a/b/../../a/b/c', 'a/./b/c', 'a\b/c']
for path in paths:
    os.path.basename(os.path.normpath(path))

如果您的文件路径没有以"/"结尾,并且目录之间用"/"分隔,则使用以下代码。正如我们所知,通常路径不会以"/"结尾。

1
2
3
import os
path_str ="/var/www/index.html"
print(os.path.basename(path_str))

但在某些情况下,比如URL以"/"结尾,然后使用以下代码

1
2
3
4
import os
path_str ="/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))

但是,当您的路径由""指定时(通常在Windows路径中找到),则可以使用以下代码

1
2
3
4
5
6
7
8
import os
path_str ="c:\\var\www\index.html"
print(os.path.basename(path_str))

import os
path_str ="c:\\home\some_str\last_str\"
split_path = path_str.rsplit("
\",1)
print(os.path.basename(split_path[0]))

您可以通过检查操作系统类型并返回结果,将两者合并为一个函数。


Windows分隔符可以是UNIX文件名或Windows路径。Unix分隔符只能存在于Unix路径中。Unix分隔符的存在表示非Windows路径。

下面将通过操作系统特定的分隔符剥离(切割尾随分隔符),然后拆分并返回最右边的值。它很难看,但基于上述假设,它很简单。如果假设不正确,请更新,我将更新此响应以匹配更准确的条件。

1
a.rstrip("\\\" if a.count("/") == 0 else '/').split("\\\" if a.count("/") == 0 else '/')[-1]

样例代码:

1
2
3
4
5
b = ['a/b/c/','a/b/c','\\a\\b\\c','\\a\\b\\c\','a\\b\\c','a/b/../../a/b/c/','a/b/../../a/b/c']

for a in b:

    print (a, a.rstrip("\" if a.count("/") == 0 else '
/').split("\" if a.count("/") == 0 else '/')[-1])


这里有一个仅限regex的解决方案,它似乎可以与任何操作系统上的任何操作系统路径一起工作。

不需要其他模块,也不需要预处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re

def extract_basename(path):
 """Extracts basename of a given path. Should Work with any OS Path on any OS"""
  basename = re.search(r'[^\\/]+(?=[\\/]?$)', path)
  if basename:
    return basename.group(0)


paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
         '
a/b/../../a/b/c/', 'a/b/../../a/b/c']

print([extract_basename(path) for path in paths])
# ['
c', 'c', 'c', 'c', 'c', 'c', 'c']


extra_paths = ['
C:\', 'alone', '/a/space in filename', 'C:\\multi
line']

print([extract_basename(path) for path in extra_paths])
# ['
C:', 'alone', 'space in filename', 'multi
line']

可以在这里测试regex。


也许只是我的多功能一体解决方案,没有重要的新功能(关于创建临时文件的tempfile:d)

1
2
3
4
import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/","").split()[-1]

得到EDOCX1[11]的值将是这样一个字符串:EDOCX1[12]所以我可以用一个空格来替换/,然后调用split()。这将返回一个列表,我得到带有[-1]的列表的最后一个元素

不需要导入任何模块。

最好的问候

4K3ND0


为了完整起见,下面是针对python 3.2+的pathlib解决方案:

1
2
3
4
5
6
7
>>> from pathlib import PureWindowsPath

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
...          '
a/b/../../a/b/c/', 'a/b/../../a/b/c']

>>> [PureWindowsPath(path).name for path in paths]
['
c', 'c', 'c', 'c', 'c', 'c', 'c']

这在Windows和Linux上都有效。


在python 2和3中,使用模块pathlib2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import posixpath  # to generate unix paths
from pathlib2 import PurePath, PureWindowsPath, PurePosixPath

def path2unix(path, nojoin=True, fromwinpath=False):
   """From a path given in any format, converts to posix path format
    fromwinpath=True forces the input path to be recognized as a Windows path (useful on Unix machines to unit test Windows paths)"""

    if not path:
        return path
    if fromwinpath:
        pathparts = list(PureWindowsPath(path).parts)
    else:
        pathparts = list(PurePath(path).parts)
    if nojoin:
        return pathparts
    else:
        return posixpath.join(*pathparts)

用途:

1
2
3
4
5
6
7
8
In [9]: path2unix('lala/lolo/haha.dat')
Out[9]: ['lala', 'lolo', 'haha.dat']

In [10]: path2unix(r'C:\lala/lolo/haha.dat')
Out[10]: ['C:\', 'lala', 'lolo', 'haha.dat']

In [11]: path2unix(r'
C:\lala/lolo/haha.dat') # works even with malformatted cases mixing both Windows and Linux path separators
Out[11]: ['
C:\', 'lala', 'lolo', 'haha.dat']

对于您的测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [12]: testcase = paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\', 'a\\b\\c',
    ...: ...     '
a/b/../../a/b/c/', 'a/b/../../a/b/c']

In [14]: for t in testcase:
    ...:     print(path2unix(t)[-1])
    ...:
    ...:
c
c
c
c
c
c
c

这里的想法是将所有路径转换为pathlib2的统一内部表示,根据平台的不同,使用不同的解码器。幸运的是,pathlib2包含一个名为PurePath的通用解码器,可以在任何路径上工作。如果不起作用,可以使用fromwinpath=True强制识别Windows路径。这将把输入字符串分成多个部分,最后一个部分是您要查找的叶,因此是path2unix(t)[-1]

如果参数nojoin=False,那么路径将被连接回去,这样输出只是转换为Unix格式的输入字符串,这对于跨平台比较子路径非常有用。


1
filename = path[path.rfind('/')+1:]