Como substituir (ou remover) uma extensão de um nome de arquivo em Python?

112

Existe uma função embutida no Python que iria substituir (ou remover, qualquer que seja) a extensão de um nome de arquivo (se houver)?

Exemplo:

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

No meu exemplo: /home/user/somefile.txtseria/home/user/somefile.jpg

Não sei se isso importa, mas preciso disso para um módulo SCons que estou escrevendo. (Então, talvez haja alguma função específica do SCons que eu possa usar?)

Eu gostaria de algo limpo . Fazer uma simples substituição de string de todas as ocorrências de .txtdentro da string obviamente não está limpo. (Isso iria falhar se meu nome de arquivo for somefile.txt.txt.txt)

ereOn
fonte
2
possível duplicata de Extraindo extensão de nome de arquivo em Python
S.Lott
SCons permite obter a base de arquivos em uma string de ação. Você pode postar a lógica específica do seu scons que precisa disso? É para a ação, emissor, scanner?
bdbaddog 01 de
parte disso parece não funcionar mais, pois o caminho retorna um PosixPath e não uma string: p
shigeta

Respostas:

146

Tente os.path.splitext, ele deve fazer o que você quiser.

import os
print os.path.splitext('/home/user/somefile.txt')[0]+'.jpg'
Jetro
fonte
15
@ S.Lott: Acredite ou não. Mas eu fiz. Eu sempre faço. Talvez com os termos errados.
Em
@ereOn: Como sua pergunta usa quase exatamente a mesma frase, estou um pouco surpreso que você não a encontrou. Sua pergunta contém 5 palavras - consecutivas - que correspondem exatamente.
S.Lott
Apenas coloque o novo nome junto com os.path.join para ter uma aparência limpa.
Tony Veijalainen
4
@Tony Veijalainen: Você não deve usar os.path.join porque isso é para unir componentes de caminho com o separador de caminho específico do sistema operacional. Por exemplo, print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')retornará /home/user/somefile/.jpg, o que não é desejável.
scottclowe
@ S.Lott - 99 pessoas votando positivamente nesta resposta claramente significa que esta postagem é útil, não há necessidade de vergonha em maiúsculas
JeffThompson
91

Expandindo a resposta de AnaPana, como remover uma extensão usando 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
JS.
fonte
1
Real Python tem um bom artigo de exemplos de casos de uso do módulo pathlib
Steven C. Howell
2
Essa resposta é minha abordagem típica, mas parece falhar quando você tem várias extensões de arquivo. Por exemplo, pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))irá imprimir 'data/foo.tar.jpg'. Suponho que você pode fazer pth.with_suffix('').with_suffix('.jpg'), mas é desajeitado, e você precisaria adicionar uma cadeia de .with_suffix('')chamadas arbitrariamente longa para lidar com um número arbitrário de pontos .em uma extensão de arquivo (reconhecidamente, mais de 2 é um caso exótico).
tel.
@tel Você poderia usar um whileloop para resolver isso:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
Dericke
Veja minha resposta abaixo para uma solução para o problema de múltiplas extensões.
Michael Hall
33

Como @jethro disse, splitexté a maneira legal de fazer isso. Mas, neste caso, é muito fácil dividir você mesmo, já que a extensão deve ser a parte do nome do arquivo que vem após o ponto final:

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

O rsplitdiz ao Python para realizar as divisões da string começando da direita da string e o 1diz para realizar no máximo uma divisão (de modo que, por exemplo, 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Como rsplitsempre retornará um array não vazio, podemos indexar 0nele com segurança para obter o nome do arquivo sem a extensão.

Katriel
fonte
8
Observe que o uso rsplitresultará em resultados diferentes para arquivos que começam com um ponto e não têm outra extensão (como arquivos ocultos no Linux, por exemplo .bashrc). os.path.splitextretorna uma extensão vazia para estes, mas usar rsplittratará todo o nome do arquivo como uma extensão.
Florian Brucker
4
Isso também fornecerá resultados inesperados para o nome do arquivo/home/john.johnson/somefile
Will Manley
7

Eu prefiro a seguinte abordagem de uma linha usando str.rsplit () :

my_filename.rsplit('.', 1)[0] + '.jpg'

Exemplo:

>>> my_filename = '/home/user/somefile.txt'
>>> my_filename.rsplit('.', 1)
>>> ['/home/user/somefile', 'txt']
IvanD
fonte
2
Isso falhará se o arquivo não tiver extensão e o usuário for 'john.doe'.
Marek Jedliński
Todos eles não falhariam então?
eatmeimadanish
6

Para 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'
AnaPana
fonte
1
Acho que a abordagem pathlib sugerida por JS. é muito mais simples.
h0b0 de
4

Tratamento de múltiplas extensões

No caso em que você tem várias extensões, este one-liner usa pathlibe str.replacefunciona muito bem:

Remover / remover extensões

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

Substituir extensões

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

Se você também quiser uma pathlibsaída de objeto, você pode, obviamente, quebrar a linhaPath()

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

Resumindo tudo em uma função

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')
Michael Hall
fonte
pathlib tem um atalho para isso: Path (). with_suffix ("") irá remover uma extensão e Path.with_suffix (". txt") irá substituí-la.
Levi
Corrigir. Mas remove apenas a primeira extensão. Portanto, no exemplo acima, usar em with_suffixvez de replaceremoveria apenas em .gzvez de .tar.gz Minha resposta deveria ser "geral", mas se você esperasse apenas uma única extensão, with_suffixseria uma solução mais limpa.
Michael Hall
3

Outra maneira de fazer é usar o str.rpartition(sep)método.

Por exemplo:

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

new_filename = prefix + '.jpg'

print new_filename
user2802945
fonte