Comment remplacer (ou supprimer) une extension d'un nom de fichier en Python?

113

Existe-t-il une fonction intégrée en Python qui remplacerait (ou supprimerait, peu importe) l'extension d'un nom de fichier (s'il en a une)?

Exemple:

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

Dans mon exemple: /home/user/somefile.txtdeviendrait/home/user/somefile.jpg

Je ne sais pas si cela compte, mais j'en ai besoin pour un module SCons que j'écris. (Alors peut-être y a-t-il une fonction spécifique à SCons que je peux utiliser?)

J'aimerais quelque chose de propre . Faire un simple remplacement de chaîne de toutes les occurrences de .txtla chaîne n'est évidemment pas propre. (Cela échouerait si mon nom de fichier est somefile.txt.txt.txt)

ereOn
la source
2
duplication possible de l' extraction de l'extension du nom de fichier en Python
S.Lott
SCons permet d'accéder à la base de fichiers dans une chaîne d'action. Pouvez-vous publier votre logique spécifique de scons qui en a besoin? Est-ce pour l'action, l'émetteur, le scanner?
bdbaddog du
une partie de cela ne semble plus fonctionner car path renvoie un PosixPath et non une chaîne: p
shigeta

Réponses:

146

Essayez os.path.splitext, il devrait faire ce que vous voulez.

import os
print os.path.splitext('/home/user/somefile.txt')[0]+'.jpg'
jethro
la source
15
@ S.Lott: Croyez-moi ou non. Mais je l'ai fait. Je fais toujours. Peut-être avec les mauvais termes.
ereOn
@ereOn: Puisque votre question utilise presque exactement le même libellé, je suis un peu surpris que vous ne l'ayez pas trouvée. Votre question comporte 5 mots consécutifs qui correspondent exactement.
S.Lott
Ne mettez le nouveau nom avec os.path.join que pour avoir l'air propre.
Tony Veijalainen
4
@Tony Veijalainen: Vous ne devez pas utiliser os.path.join car c'est pour joindre des composants de chemin avec le séparateur de chemin spécifique au système d'exploitation. Par exemple, print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')retournera /home/user/somefile/.jpg, ce qui n'est pas souhaitable.
scottclowe
@ S.Lott - 99 personnes qui votent pour cette réponse signifie assez clairement que ce message est utile, pas besoin de honte en majuscules
JeffThompson
92

En développant la réponse d'AnaPana, comment supprimer une extension à l'aide de 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.
la source
1
Real Python a une bonne rédaction d'exemples de cas d'utilisation du module pathlib
Steven C. Howell
2
Cette réponse est mon approche typique, mais elle semble échouer lorsque vous avez plusieurs extensions de fichier. Par exemple, pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))sortira 'data/foo.tar.jpg'. Je suppose que vous pouvez le faire pth.with_suffix('').with_suffix('.jpg'), mais c'est maladroit, et vous auriez besoin d'ajouter une chaîne d' .with_suffix('')appels arbitrairement longue afin de traiter un nombre arbitraire de points .dans une extension de fichier (certes, plus de 2 est un cas de pointe exotique).
tél
@tel Vous pouvez utiliser une whileboucle pour résoudre ce problème:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
dericke
Voir ma réponse ci-dessous pour une solution au problème des extensions multiples.
Michael Hall
33

Comme l'a dit @jethro, splitextc'est la meilleure façon de le faire. Mais dans ce cas, il est assez facile de le diviser vous-même, puisque l'extension doit être la partie du nom de fichier venant après la dernière période:

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

Le rsplitdit à Python d'effectuer le fractionnement de chaîne en commençant par la droite de la chaîne, et le 1dit d'effectuer au plus un fractionnement (de sorte que par exemple 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Puisque rsplitretournera toujours un tableau non vide, nous pouvons en toute sécurité l'indexer 0pour obtenir le nom de fichier moins l'extension.

Katriel
la source
8
Notez que l'utilisation rsplitentraînera des résultats différents pour les fichiers commençant par un point et n'ayant pas d'autre extension (comme les fichiers cachés sous Linux, par exemple .bashrc). os.path.splitextrenvoie une extension vide pour ceux-ci, mais l'utilisation rsplittraitera le nom de fichier entier comme une extension.
Florian Brucker
4
Cela donnera également des résultats inattendus pour le nom de fichier/home/john.johnson/somefile
Will Manley
7

Je préfère l'approche à une ligne suivante en utilisant str.rsplit () :

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

Exemple:

>>> my_filename = '/home/user/somefile.txt'
>>> my_filename.rsplit('.', 1)
>>> ['/home/user/somefile', 'txt']
IvanD
la source
2
Cela échoue si le somefile n'a pas d'extension et que l'utilisateur est «john.doe».
Marek Jedliński
N'échoueraient-ils pas tous alors?
eatmeimadanish
6

Pour 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
la source
1
Je pense que l'approche pathlib suggérée par JS. est beaucoup plus simple.
h0b0
4

Gérer plusieurs extensions

Dans le cas où vous avez plusieurs extensions, ce one-liner utilise pathlibet str.replacefonctionne un régal:

Supprimer / supprimer les extensions

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

Remplacer les extensions

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

Si vous voulez également une pathlibsortie d'objet, vous pouvez évidemment envelopper la ligne dansPath()

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

Tout emballer dans une fonction

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
la source
pathlib a un raccourci pour cela: Path (). with_suffix ("") supprimera une extension et Path.with_suffix (". txt") la remplacera.
Levi
Correct. Mais cela ne supprime que la première extension. Donc, dans l'exemple ci-dessus, utiliser à la with_suffixplace de replacene supprimerait qu'à la .gzplace de .tar.gz Ma réponse était censée être "générale", mais si vous n'attendez qu'une seule extension, ce with_suffixserait une solution plus propre.
Michael Hall le
3

Une autre façon de faire est d'utiliser la str.rpartition(sep)méthode.

Par exemple:

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

new_filename = prefix + '.jpg'

print new_filename
user2802945
la source