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

ere*_*eOn 87 python scons

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

例:

print replace_extension('/home/user/somefile.txt', '.jpg')
Run Code Online (Sandbox Code Playgroud)

在我的例子中:/home/user/somefile.txt将成为/home/user/somefile.jpg

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

我想要干净的东西.对字符串中的所有实例进行简单的字符串替换.txt显然不是很干净.(如果我的文件名是这会失败somefile.txt.txt.txt)

jet*_*hro 122

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

import os
print os.path.splitext('/home/user/somefile.txt')[0]+'.jpg'
Run Code Online (Sandbox Code Playgroud)

  • @ S.Lott:信不信由你.但我做到了.我经常做.也许是错误的条款. (10认同)
  • @Tony Veijalainen:您不应该使用os.path.join,因为这是为了使用特定于操作系统的路径分隔符连接路径组件.例如,`print os.path.join(os.path.splitext('/ home/user/somefile.txt')[0],'.jpg')`将返回`/home/user/somefile/.jpg `,这是不可取的. (4认同)
  • 显式优于隐式。如果有零个或一个后缀,则: `pathlib.Path('/home/user/somefile.txt').with_suffix('.jpg')` (4认同)
  • @ereOn:此外,将来首先尝试SEARCH.它可以更好地回答这些标准问题. (2认同)

JS.*_*JS. 53

扩展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
Run Code Online (Sandbox Code Playgroud)

  • Real Python 对 pathlib 模块的示例用例有很好的描述:https://realpython.com/python-pathlib/ (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 是一种奇特的边缘情况)。 (2认同)
  • @tel你可以使用`while`循环来解决这个问题:`pth = Path('data/foo.tar.gz'); 而 pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')` (2认同)

Kat*_*iel 28

正如@jethro所说,这splitext是一种巧妙的方式.但在这种情况下,自己拆分它很容易,因为扩展必须是最后一段时间后文件名的一部分:

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

rsplit告诉Python来执行从字符串的右侧开始字符串分割,并1说执行至多一个分裂(从而使得例如'foo.bar.baz'- > [ 'foo.bar', 'baz' ]).由于rsplit将始终返回非空数组,我们可以安全地索引0它以获取文件名减去扩展名.

  • 请注意,使用`rsplit`将导致以点开头并且没有其他扩展名的文件(例如Linux上的隐藏文件,例如`.bashrc`)会产生不同的结果.`os.path.splitext`为这些返回一个空的扩展名,但使用`rsplit`会将整个文件名视为扩展名. (7认同)
  • 这也会给文件名`/ home/john.johnson/somefile`带来意想不到的结果 (3认同)

Iva*_*anD 11

我更喜欢使用str.rsplit()的以下单行方法:

my_filename.rsplit('.', 1)[0] + '.jpg'
Run Code Online (Sandbox Code Playgroud)

例子:

>>> my_filename = '/home/user/somefile.txt'
>>> my_filename.rsplit('.', 1)
>>> ['/home/user/somefile', 'txt']
Run Code Online (Sandbox Code Playgroud)

  • 如果 somefile 没有扩展名并且用户是 'john.doe',这将失败。 (3认同)
  • 那他们岂不是都失败了? (3认同)

Mic*_*all 11

处理多个扩展

如果您有多个扩展使用pathlibstr.replace工作治疗:

删除/剥离扩展

>>> from pathlib import Path
>>> p = Path("/path/to/myfile.tar.gz")
>>> extensions = "".join(p.suffixes)

# any python version
>>> str(p).replace(extensions, "")
'/path/to/myfile'

# python>=3.9
>>> str(p).removesuffix(extensions)
'/path/to/myfile'
Run Code Online (Sandbox Code Playgroud)

替换扩展

>>> p = Path("/path/to/myfile.tar.gz")
>>> extensions = "".join(p.suffixes)
>>> new_ext = ".jpg"
>>> str(p).replace(extensions, new_ext)
'/path/to/myfile.jpg'
Run Code Online (Sandbox Code Playgroud)

如果您还想要一个pathlib对象输出,那么您显然可以将行包起来Path()

>>> Path(str(p).replace("".join(p.suffixes), ""))
PosixPath('/path/to/myfile')
Run Code Online (Sandbox Code Playgroud)

将其全部包装在一个函数中

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')
    
Run Code Online (Sandbox Code Playgroud)

  • 正确的。但它只删除第一个扩展。因此,在上面的示例中,使用“with_suffix”而不是“replace”只会删除“.gz”而不是“.tar.gz”。我的答案是“一般”的,但如果您只期望一个扩展名,“ with_suffix` 将是一个更干净的解决方案。 (4认同)
  • 从 Python 3.9 开始,您可以使用“removesuffix”而不是“replace”。这也许更安全,例如在 Linux 上,某些 *目录* 可能有 `.d` 后缀:`"/home/config.d/file.d".replace(".d", "")` -> `' /home/config/file'` 与 `"/home/config.d/file.d".removesuffix(".d")` -> `'/home/config.d/file'`。因此,还保存了“””函数参数。 (3认同)
  • pathlib 有一个快捷方式: Path().with_suffix("") 将删除扩展名,而 Path.with_suffix(".txt") 将替换它。 (2认同)

jis*_*l18 9

TLDR: 在我看来,替换所有扩展的最佳方法如下。

import pathlib
p = pathlib.Path('/path/to.my/file.foo.bar.baz.quz')
print(p.with_name(p.name.split('.')[0]).with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

更长的答案: 执行此操作的最佳方法取决于您的 python 版本以及需要处理的扩展数量。也就是说,我很惊讶没有人提到 pathlib 的with_name. 我还担心这里的一些答案不处理.父目录中的 a 。以下是完成扩展替换的几种方法。

使用路径对象

更换最多 1 个分机

import pathlib
p = pathlib.Path('/path/to.my/file.foo.bar.baz.quz')
print(p.with_name(p.name.split('.')[0]).with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

更换最多两个扩展

import pathlib
p = pathlib.Path('/path/to.my/file.foo')
print(p.with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

替换所有扩展

使用pathlibs with_name(我认为最好的解决方案):

import pathlib
p = pathlib.Path('/path/to.my/file.foo.bar')
print(p.with_name(p.stem).with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

使用functools.reduce和pathlib的with_suffix

import pathlib
p = pathlib.Path('/path/to.my/file.foo.bar.baz.quz')
print(p.with_name(p.name.split('.')[0]).with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

Python 3.9+使用 pathlib 和 str.removesuffix:

import pathlib
import functools
p = pathlib.Path('/path/to.my/file.foo.bar.baz.quz')
print(functools.reduce(lambda v, _: v.with_suffix(''), p.suffixes, p).with_suffix('.jpg'))
print(functools.reduce(lambda v, e: v.with_suffix(e), ['' for _ in p.suffixes] + ['.jpg'], p))
Run Code Online (Sandbox Code Playgroud)

不使用路径对象(仅限字符串)

一般来说,我认为使用 pathlib 的解决方案更干净,但并不是每个人都能做到这一点。如果您仍在使用 python 2,我很抱歉。如果你没有 python2 的 pathlib 包,我真的很抱歉。

替换所有扩展

Python 2.7 兼容使用os.path

import pathlib
p = pathlib.Path('/path/to.my/file.foo.bar.baz.quz')
print(pathlib.Path(str(p).removesuffix(''.join(p.suffixes))).with_suffix('.jpg'))
Run Code Online (Sandbox Code Playgroud)

Python 3.9+使用removesuffixand os.path(如果你有 python3.9,为什么不使用pathlib?):

import os
ps = '/path/to.my/file.foo.bar.baz.quz'
print(os.path.join(os.path.dirname(ps), os.path.basename(ps).split('.')[0] + '.jpg'))
Run Code Online (Sandbox Code Playgroud)


小智 6

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

例如:

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

new_filename = prefix + '.jpg'

print new_filename
Run Code Online (Sandbox Code Playgroud)


Ana*_*ana 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'
Run Code Online (Sandbox Code Playgroud)

  • 我认为 JS 建议的 pathlib 方法。简单得多。 (2认同)