¿Cómo reemplazar (o quitar) una extensión de un nombre de archivo en Python?

112

¿Existe una función incorporada en Python que reemplace (o elimine, lo que sea) la extensión de un nombre de archivo (si tiene una)?

Ejemplo:

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

En mi ejemplo: /home/user/somefile.txtse convertiría/home/user/somefile.jpg

No sé si importa, pero necesito esto para un módulo SCons que estoy escribiendo. (Entonces, ¿quizás haya alguna función específica de SCons que pueda usar?)

Quisiera algo limpio . Hacer un simple reemplazo de cadena de todas las ocurrencias .txtdentro de la cadena obviamente no es limpio. (Esto fallaría si mi nombre de archivo es somefile.txt.txt.txt)

ereOn
fuente
SCons permite acceder a la base de archivos en una cadena de acción. ¿Puedes publicar tu lógica específica de scons que necesita esto? ¿Es esto para la acción, emisor, escáner?
bdbaddog
algo de esto parece no funcionar más ya que la ruta devuelve un PosixPath, no una cadena: p
shigeta

Respuestas:

146

Prueba os.path.splitext , debería hacer lo que quieras.

import os
print os.path.splitext('/home/user/somefile.txt')[0]+'.jpg'
jethro
fuente
15
@ S.Lott: Créame o no. Pero lo hice. Siempre hago. Quizás con los términos equivocados.
ere el
@ereOn: Dado que su pregunta usa casi exactamente la misma redacción, me sorprende un poco que no la haya encontrado. Su pregunta tiene 5 palabras, seguidas, que coinciden con precisión.
S.Lott
Solo ponga el nuevo nombre junto con os.path.join para que se vea limpio.
Tony Veijalainen
4
@Tony Veijalainen: No debe usar os.path.join porque es para unir componentes de ruta con el separador de ruta específico del sistema operativo. Por ejemplo, print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')volverá /home/user/somefile/.jpg, lo que no es deseable.
scottclowe
@ S.Lott - 99 personas votaron a favor de esta respuesta con bastante claridad significa que esta publicación es útil, no hay necesidad de avergonzar en mayúsculas
JeffThompson
92

Ampliando la respuesta de AnaPana, cómo eliminar una extensión 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.
fuente
1
Real Python tiene una buena descripción de casos de uso de ejemplo del módulo pathlib
Steven C. Howell
2
Esta respuesta es mi enfoque típico, pero parece fallar cuando tiene varias extensiones de archivo. Por ejemplo, pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))saldrá 'data/foo.tar.jpg'. Supongo que puede hacerlo pth.with_suffix('').with_suffix('.jpg'), pero es torpe, y necesitaría agregar una cadena de .with_suffix('')llamadas arbitrariamente larga para lidiar con un número arbitrario de puntos .en una extensión de archivo (es cierto que más de 2 es un caso extremo exótico).
tel
@tel Podrías usar un whilebucle para resolver eso:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
dericke
Vea mi respuesta a continuación para obtener una solución al problema de múltiples extensiones.
Michael Hall
33

Como dijo @jethro, splitextes la mejor manera de hacerlo. Pero en este caso, es bastante fácil dividirlo usted mismo, ya que la extensión debe ser la parte del nombre del archivo que viene después del período final:

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

Le rsplitdice a Python que realice las divisiones de cadenas comenzando desde la derecha de la cadena, y 1dice que realice como máximo una división (por ejemplo, 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Dado rsplitque siempre devolverá una matriz no vacía, podemos indexarla con seguridad 0para obtener el nombre del archivo menos la extensión.

Katriel
fuente
8
Tenga en cuenta que el uso rsplitdará como resultado resultados diferentes para los archivos que comienzan con un punto y no tienen otra extensión (como archivos ocultos en Linux, por ejemplo .bashrc). os.path.splitextdevuelve una extensión vacía para estos, pero el uso rsplittratará el nombre de archivo completo como una extensión.
Florian Brucker
4
Esto también dará resultados inesperados para el nombre de archivo/home/john.johnson/somefile
Will Manley
7

Prefiero el siguiente enfoque de una sola línea usando str.rsplit () :

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

Ejemplo:

>>> my_filename = '/home/user/somefile.txt'
>>> my_filename.rsplit('.', 1)
>>> ['/home/user/somefile', 'txt']
IvanD
fuente
2
Esto falla si el archivo somefile no tiene extensión y el usuario es 'john.doe'.
Marek Jedliński
¿No fallarían todos entonces?
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
fuente
1
Creo que el enfoque de pathlib sugerido por JS. es mucho más simple.
h0b0
4

Manejo de múltiples extensiones

En el caso de que tenga varias extensiones, este de una sola línea usa pathliby str.replacefunciona de maravilla:

Quitar / quitar extensiones

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

Reemplazar extensiones

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

Si también desea una pathlibsalida de objeto, obviamente puede ajustar la línea enPath()

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

Envolviendo todo en una función

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
fuente
pathlib tiene un atajo para esto: Path (). with_suffix ("") eliminará una extensión y Path.with_suffix (". txt") la reemplazará.
Levi
Correcto. Pero solo elimina la primera extensión. Entonces, en el ejemplo anterior, usar en with_suffixlugar de replacesolo eliminaría en .gzlugar de .tar.gz Mi respuesta tenía la intención de ser "general", pero si solo espera una sola extensión, with_suffixsería una solución más limpia.
Michael Hall
3

Otra forma de hacerlo es utilizar el str.rpartition(sep)método.

Por ejemplo:

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

new_filename = prefix + '.jpg'

print new_filename
user2802945
fuente