Wie ersetze (oder entferne) ich eine Erweiterung von einem Dateinamen in Python?


110

Gibt es in Python eine integrierte Funktion, die die Erweiterung eines Dateinamens (falls vorhanden) ersetzt (oder entfernt)?

Beispiel:

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

In meinem Beispiel: /home/user/somefile.txtwürde werden/home/user/somefile.jpg

Ich weiß nicht, ob es wichtig ist, aber ich brauche dies für ein SCons-Modul, das ich schreibe. (Vielleicht gibt es einige SCons-spezifische Funktionen, die ich verwenden kann?)

Ich hätte gerne etwas Sauberes . Ein einfacher String-Austausch aller Vorkommen .txtinnerhalb des Strings ist offensichtlich nicht sauber. (Dies würde fehlschlagen, wenn mein Dateiname ist somefile.txt.txt.txt)



Mit SCons können Sie in einer Aktionszeichenfolge auf die Dateibasis zugreifen. Können Sie Ihre Scons-spezifische Logik veröffentlichen, die dies benötigt? Ist das für die Aktion, Emitter, Scanner?
Bdbaddog

Einiges davon scheint nicht mehr zu funktionieren, da der Pfad einen PosixPath zurückgibt, keinen String: p
shigeta

Antworten:


146

Versuchen Sie os.path.splitext, es sollte tun, was Sie wollen.

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

15
@ S.Lott: Glaub mir oder nicht. Hab ich doch. Mache ich immer. Vielleicht mit den falschen Begriffen.
Ereon

@ereOn: Da Ihre Frage fast genau die gleiche Formulierung verwendet, bin ich ein wenig überrascht, dass Sie sie nicht gefunden haben. Ihre Frage enthält 5 Wörter hintereinander, die genau übereinstimmen.
S.Lott

Fügen Sie den neuen Namen nur zusammen mit os.path.join ein, um sauber auszusehen.
Tony Veijalainen

4
@ Tony Veijalainen: Sie sollten os.path.join nicht verwenden, da dies zum Verbinden von Pfadkomponenten mit dem betriebssystemspezifischen Pfadtrennzeichen dient. Zum Beispiel print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')wird zurückkehren /home/user/somefile/.jpg, was nicht wünschenswert ist.
Scottclowe

@ S.Lott - 99 Leute stimmen diese Antwort ziemlich deutlich ab, was bedeutet, dass dieser Beitrag hilfreich ist, keine Notwendigkeit für All-Caps-
Scham

90

Erweitern Sie die Antwort von AnaPana, wie Sie eine Erweiterung mit pathlib entfernen (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 hat eine gute Beschreibung von Beispielanwendungsfällen des Pathlib-Moduls: realpython.com/python-pathlib
Steven C. Howell

2
Diese Antwort ist mein typischer Ansatz, scheint jedoch zu scheitern, wenn Sie mehrere Dateierweiterungen haben. pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))Wird zum Beispiel ausgegeben 'data/foo.tar.jpg'. Ich nehme an, Sie können dies tun pth.with_suffix('').with_suffix('.jpg'), aber es ist umständlich, und Sie müssten eine beliebig lange Kette von .with_suffix('')Aufrufen hinzufügen , um mit einer beliebigen Anzahl von Punkten .in einer Dateierweiterung umgehen zu können (zugegebenermaßen ist mehr als 2 ein exotischer Randfall).
Tel

@tel Sie könnten eine whileSchleife verwenden, um das zu lösen:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
dericke

In meiner Antwort unten finden Sie eine Lösung für das Problem mit mehreren Erweiterungen.
Michael Hall

32

Wie @jethro sagte, splitextist der ordentliche Weg, es zu tun. In diesem Fall ist es jedoch ziemlich einfach, es selbst aufzuteilen, da die Erweiterung der Teil des Dateinamens sein muss, der nach dem letzten Zeitraum kommt:

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

Das rsplitweist Python an, die Zeichenfolgensplits beginnend rechts von der Zeichenfolge 1durchzuführen , und das sagt, dass höchstens eine Teilung durchgeführt werden soll (z . B. 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Da rsplitimmer ein nicht leeres Array zurückgegeben wird, können wir sicher darin indizieren 0, um den Dateinamen abzüglich der Erweiterung zu erhalten.


8
Beachten Sie, dass die Verwendung rsplitzu unterschiedlichen Ergebnissen für Dateien führt, die mit einem Punkt beginnen und keine andere Erweiterung haben (wie z .bashrc. B. versteckte Dateien unter Linux ). os.path.splitextGibt für diese eine leere Erweiterung zurück, bei Verwendung rsplitwird jedoch der gesamte Dateiname als Erweiterung behandelt.
Florian Brucker

4
Dies wird auch unerwartete Ergebnisse für den Dateinamen/home/john.johnson/somefile
Will Manley

7

Ich bevorzuge den folgenden Einzeiler -Ansatz mit str.rsplit () :

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

Beispiel:

>>> my_filename = '/home/user/somefile.txt'
>>> my_filename.rsplit('.', 1)
>>> ['/home/user/somefile', 'txt']

2
Dies schlägt fehl, wenn die Somefile keine Erweiterung hat und der Benutzer 'john.doe' ist.
Marek Jedliński

Würden sie dann nicht alle scheitern?
Eatmeimadanish

6

Für 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
Ich denke, der von JS vorgeschlagene Pathlib-Ansatz. ist viel einfacher.
h0b0

4

Umgang mit mehreren Erweiterungen

Für den Fall, dass Sie mehrere Erweiterungen haben, verwendet dieser Einzeiler pathlibund str.replacefunktioniert ein Vergnügen:

Verlängerungen entfernen / entfernen

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

Erweiterungen ersetzen

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

Wenn Sie auch eine pathlibObjektausgabe wünschen , können Sie die Zeile natürlich einschließenPath()

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

Alles in eine Funktion einwickeln

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 hat eine Verknüpfung dafür: Path (). with_suffix ("") entfernt eine Erweiterung und Path.with_suffix (". txt") ersetzt sie.
Levi

Richtig. Es wird jedoch nur die erste Erweiterung entfernt. Im obigen Beispiel sollte die Verwendung von with_suffixanstelle von replacenur .gzanstelle von .tar.gz Meine Antwort "allgemein" sein. Wenn Sie jedoch nur eine einzige Erweiterung erwarten, with_suffixwäre dies eine sauberere Lösung.
Michael Hall

3

Eine andere Möglichkeit ist die Verwendung der str.rpartition(sep)Methode.

Beispielsweise:

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

new_filename = prefix + '.jpg'

print new_filename
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.