如何在Python中从文件名替换(或剥离)扩展名?


112

Python中是否有内置函数可以替换(或删除,无论如何)文件名的扩展名(如果有扩展名)?

例:

print replace_extension('/home/user/somefile.txt', '.jpg')

在我的示例中:/home/user/somefile.txt将变为/home/user/somefile.jpg

我不知道这是否重要,但是我正在编写的SCons模块需要它。(所以也许有一些我可以使用的SCons特定功能?)

我想要一些干净的东西。对所有出现.txt在字符串中的字符串进行简单的字符串替换显然并不干净。(如果我的文件名是,这将失败somefile.txt.txt.txt



SCons允许通过操作字符串访问文件库。您可以发布特定于此的scons特定逻辑吗?这是用于动作,发射器,扫描器吗?
bdbaddog 2015年

由于路径返回的是PosixPath而不是字符串,因此其中一些似乎不再起作用:p
shigeta

Answers:


146

试试os.path.splitext它应该做你想要的。

import os
print os.path.splitext('/home/user/somefile.txt')[0]+'.jpg'

15
@ S.Lott:信不信由你。但是我做到了。我经常做。也许用错误的术语。
ereOn 2010年

@ereOn:由于您的问题几乎使用了完全相同的措词,因此您没有找到我感到有些惊讶。您的问题有5个字-连续-完全匹配。
S.Lott

仅将新名称与os.path.join放在一起才能看起来干净。
Tony Veijalainen,2010年

4
@Tony Veijalainen:您不应使用os.path.join,因为这是用于使用特定于操作系统的路径分隔符来连接路径组件。例如,print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')将返回/home/user/somefile/.jpg,这是不希望的。
scottclowe

@ S.Lott –投票赞成这个答案的99个人非常清楚,这意味着该帖子很有帮助,无需全力以赴
JeffThompson

92

扩展AnaPana的答案,即如何使用pathlib(Python> = 3.4)删除扩展:

>>> from pathlib import Path

>>> filename = Path('/some/path/somefile.txt')

>>> filename_wo_ext = filename.with_suffix('')

>>> filename_replace_ext = filename.with_suffix('.jpg')

>>> print(filename)
/some/path/somefile.ext    

>>> print(filename_wo_ext)
/some/path/somefile

>>> print(filename_replace_ext)
/some/path/somefile.jpg

1
Real Python很好地记录了pathlib模块的用例示例:realpython.com/python-pathlib
Steven C. Howell,

2
这个答案是我的典型方法,但是当您具有多个文件扩展名时,它似乎会失败。例如,pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))将输出'data/foo.tar.jpg'。我想您可以做到pth.with_suffix('').with_suffix('.jpg'),但是它很笨拙,并且您需要添加任意长的.with_suffix('')调用链,以便处理.文件扩展名中任意数量的点(诚​​然,超过2个是特殊的边缘情况)。
电话

@tel您可以使用while循环来解决此问题:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
取消

请参阅下面答案,以解决多重扩展问题。
迈克尔·霍尔

33

就像@jethro所说的那样,splitext是一种很好的方法。但是在这种情况下,您可以很容易地自己拆分它,因为扩展名必须是最后一个句点之后的文件名的一部分:

filename = '/home/user/somefile.txt'
print( filename.rsplit( ".", 1 )[ 0 ] )
# '/home/user/somefile'

rsplit告诉Python从字符串的右边开始执行字符串分割,而告诉Python 1最多执行一个分割(例如'foo.bar.baz'-> [ 'foo.bar', 'baz' ])。由于rsplit将始终返回一个非空数组,因此我们可以安全地对其进行索引0以获取文件名减去扩展名。


8
请注意,rsplit对于以点开头且没有其他扩展名的文件(例如Linux上的隐藏文件.bashrc),使用会导致不同的结果。os.path.splitext返回这些扩展名的空扩展名,但是使用rsplit会将整个文件名视为扩展名。
Florian Brucker

4
这也会给文件名带来意外的结果/home/john.johnson/somefile
Will Manley


6

对于Python> = 3.4:

from pathlib import Path

filename = '/home/user/somefile.txt'

p = Path(filename)
new_filename = p.parent.joinpath(p.stem + '.jpg') # PosixPath('/home/user/somefile.jpg')
new_filename_str = str(new_filename) # '/home/user/somefile.jpg'

1
我认为JS建议使用pathlib方法。更简单。
h0b0

4

处理多个扩展

如果您有多个扩展名,则此单行代码使用pathlibstr.replace有效对待:

删除/扩展扩展名

>>> from pathlib import Path
>>> p = Path("/path/to/myfile.tar.gz")
>>> str(p).replace("".join(p.suffixes), "")
'/path/to/myfile'

替换扩展名

>>> p = Path("/path/to/myfile.tar.gz")
>>> new_ext = ".jpg"
>>> str(p).replace("".join(p.suffixes), new_ext)
'/path/to/myfile.jpg'

如果您还需要pathlib对象输出,那么显然可以将行换行Path()

>>> Path(str(p).replace("".join(p.suffixes), ""))
PosixPath('/path/to/myfile')

将所有内容包装在一个函数中

from pathlib import Path
from typing import Union

PathLike = Union[str, Path]


def replace_ext(path: PathLike, new_ext: str = "") -> Path:
    extensions = "".join(Path(path).suffixes)
    return Path(str(p).replace(extensions, new_ext))


p = Path("/path/to/myfile.tar.gz")
new_ext = ".jpg"

assert replace_ext(p, new_ext) == Path('/path/to/myfile.jpg')
assert replace_ext(str(p), new_ext) == Path('/path/to/myfile.jpg')
assert replace_ext(p) == Path('/path/to/myfile')

pathlib为此提供了一个快捷方式:Path()。with_suffix(“”)将删除扩展名,而Path.with_suffix(“。txt”)将替换它。
列维

正确。但它只会删除第一个扩展名。因此,在上面的示例中,使用with_suffix代替replace只会删除.gz而不是代替.tar.gz 我的回答是“一般性的”,但是,如果您只期望一个扩展名,那with_suffix将是一个更干净的解决方案。
Michael Hall

3

另一种方法是使用该str.rpartition(sep)方法。

例如:

filename = '/home/user/somefile.txt'
(prefix, sep, suffix) = filename.rpartition('.')

new_filename = prefix + '.jpg'

print new_filename
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.