Extrahieren der Erweiterung aus dem Dateinamen in Python

1300

Gibt es eine Funktion zum Extrahieren der Erweiterung aus einem Dateinamen?

Alex
quelle

Antworten:

1990

Ja. Verwendung os.path.splitext(siehe Python 2.X-Dokumentation oder Python 3.X-Dokumentation ):

>>> import os
>>> filename, file_extension = os.path.splitext('/path/to/somefile.ext')
>>> filename
'/path/to/somefile'
>>> file_extension
'.ext'

Im Gegensatz zu den meisten manuellen Versuchen zum Teilen von Zeichenfolgen os.path.splitextwird korrekt behandelt /a/b.c/d, dass keine Erweiterung statt Erweiterung vorhanden ist .c/d, und es wird so behandelt .bashrc, dass keine Erweiterung statt Erweiterung vorhanden ist .bashrc:

>>> os.path.splitext('/a/b.c/d')
('/a/b.c/d', '')
>>> os.path.splitext('.bashrc')
('.bashrc', '')
nosklo
quelle
15
Die Verwendung von basenameist hier ein wenig verwirrend, da zurückkehren os.path.basename("/path/to/somefile.ext")würde"somefile.ext"
Jiaaro
17
wäre nicht endswith()tragbarer und pythonischer?
Sebastian Mach
79
@ klingt.net Na ja, in diesem Fall .asdist das wirklich die Erweiterung !! Wenn Sie darüber nachdenken, foo.tar.gzhandelt es sich um eine gzip-komprimierte Datei ( .gz), die zufällig eine TAR-Datei ( .tar) ist. Aber es ist in erster Linie eine gzip-Datei . Ich würde nicht erwarten, dass es die doppelte Erweiterung überhaupt zurückgibt.
Nosklo
159
Die Standard-Namenskonvention für Python-Funktionen ist wirklich ärgerlich - fast jedes Mal, wenn ich sie nachschlage, verwechsle ich sie als solche splittext. Wenn sie nur irgendetwas tun würden, um den Bruch zwischen Teilen dieses Namens zu kennzeichnen, wäre es viel einfacher zu erkennen, dass es splitExtoder ist split_ext. Sicher kann ich nicht die einzige Person sein, die diesen Fehler gemacht hat?
ArtOfWarfare
9
@Vingtoft Sie haben in Ihrem Kommentar nichts über werkzeugs FileStorage erwähnt, und diese Frage hat nichts mit diesem bestimmten Szenario zu tun. Möglicherweise stimmt etwas nicht mit der Übergabe des Dateinamens. os.path.splitext('somefile.ext')=> ('somefile', '.ext'). Geben Sie ein Beispiel für einen tatsächlichen Zähler an, ohne auf eine Bibliothek eines Drittanbieters zu verweisen.
Gewthen
400
import os.path
extension = os.path.splitext(filename)[1]
Brian Neal
quelle
15
Warum aus Neugier import os.pathstatt warum from os import path?
Kiswa
2
Oh, ich habe mich nur gefragt, ob es einen bestimmten Grund dafür gibt (außer Konvention). Ich lerne immer noch Python und wollte mehr lernen!
Kiswa
55
Es hängt wirklich davon ab, ob from os import pathder Name pathin Ihrem lokalen Bereich verwendet wird. Auch andere, die sich den Code ansehen, wissen möglicherweise nicht sofort, dass der Pfad der Pfad vom Betriebssystemmodul ist. Wo, als ob Sie es verwenden import os.path, bleibt es im osNamespace und wo immer Sie den Anruf tätigen, wissen die Leute sofort, dass es path()vom osModul stammt.
Dennmat
18
Ich weiß, dass es semantisch nicht anders ist, aber ich persönlich finde die Konstruktion _, extension = os.path.splitext(filename)viel schöner.
Tim Gilbert
3
Wenn Sie die Erweiterung als Teil eines komplexeren Ausdrucks wünschen, kann die [1] nützlicher sein: if check_for_gzip and os.path.splitext(filename)[1] == '.gz':
gerardw
239

Neu in Version 3.4.

import pathlib

print(pathlib.Path('yourPath.example').suffix) # '.example'

Ich bin überrascht, dass noch niemand erwähnt pathlibhat, pathlibIST großartig!

Wenn Sie alle Suffixe benötigen (z. B. wenn Sie ein haben .tar.gz), .suffixeswird eine Liste von ihnen zurückgegeben!

jeromej
quelle
12
Beispiel für das ''.join(pathlib.Path('somedir/file.tar.gz').suffixes)
Abrufen von
Gute Antwort. Ich fand dieses Tutorial nützlicher als die Dokumentation: zetcode.com/python/pathlib
user118967
@ user3780389 Wäre ein "foo.bar.tar.gz" nicht immer noch ein gültiges ".tar.gz"? In diesem Fall sollte Ihr Snippet verwendet werden, .suffixes[-2:]um sicherzustellen, dass höchstens .tar.gz angezeigt wird.
Jeromej
111
import os.path
extension = os.path.splitext(filename)[1][1:]

Um nur den Text der Erweiterung ohne den Punkt zu erhalten.

Wonzbak
quelle
73

Eine Option kann das Aufteilen vom Punkt sein:

>>> filename = "example.jpeg"
>>> filename.split(".")[-1]
'jpeg'

Kein Fehler, wenn die Datei keine Erweiterung hat:

>>> "filename".split(".")[-1]
'filename'

Aber Sie müssen vorsichtig sein:

>>> "png".split(".")[-1]
'png'    # But file doesn't have an extension
Murat Çorlu
quelle
4
Dies würde sich aufregen, wenn Sie x.tar.gz
Kirill
19
Nicht wirklich. Die Erweiterung einer Datei mit dem Namen "x.tar.gz" ist "gz" und nicht "tar.gz". os.path.splitext gibt auch ".os" als Erweiterung an.
Murat Çorlu
1
können wir [1] anstelle von [-1] verwenden? Ich konnte [-1] mit split nicht verstehen
user765443
7
[-1], um das letzte Element von Elementen zu erhalten, die durch einen Punkt geteilt wurden. Beispiel:"my.file.name.js".split('.') => ['my','file','name','js]
Murat Çorlu
1
@BenjaminR ah ok, Sie nehmen eine Optimierung der Ergebnisliste vor. ['file', 'tar', 'gz']mit 'file.tar.gz'.split('.') vs ['file.tar', 'gz'] mit 'file.tar.gz'.rsplit('.', 1). Ja, könnte sein.
Murat Çorlu
40

Es lohnt sich, dort einen niedrigeren Wert hinzuzufügen, damit Sie sich nicht fragen, warum die JPGs nicht in Ihrer Liste angezeigt werden.

os.path.splitext(filename)[1][1:].strip().lower()
mischte
quelle
19

Alle oben genannten Lösungen funktionieren, aber unter Linux habe ich festgestellt, dass am Ende der Erweiterungszeichenfolge eine neue Zeile steht, die den Erfolg von Übereinstimmungen verhindert. Fügen Sie die strip()Methode am Ende hinzu. Zum Beispiel:

import os.path
extension = os.path.splitext(filename)[1][1:].strip() 
yamex5
quelle
1
Könnten Sie bitte zum besseren Verständnis erklären, gegen welches zusätzliche Verhalten der zweite Index / Slice schützt? (dh das [1:]in .splittext(filename)[1][1:]) - danke im Voraus
Samuel Harmer
1
Ich habe es selbst herausgefunden: splittext()(anders als wenn Sie eine Zeichenfolge mit '.' Teilen) enthält das '.' Zeichen in der Erweiterung. Das zusätzliche [1:]wird es los.
Samuel Harmer
17

Mit splitext gibt es Probleme mit Dateien mit doppelter Erweiterung (zB file.tar.gz, file.tar.bz2, etc ..)

>>> fileName, fileExtension = os.path.splitext('/path/to/somefile.tar.gz')
>>> fileExtension 
'.gz'

sollte aber sein: .tar.gz

Die möglichen Lösungen sind hier

XavierCLL
quelle
35
Nein, es sollte .gz sein
Robert Siemer
1
zweimal machen, um die 2 Erweiterungen zu bekommen?
Maazza
1
@maazza yep. gunzip somefile.tar.gz Wie lautet der Ausgabedateiname?
FlipMcF
1
Deshalb haben wir die Erweiterung 'tgz', was bedeutet: tar + gzip! : D
Nuno Aniceto
1
@peterhil Ich glaube nicht, dass Sie möchten, dass Ihr Python-Skript die Anwendung kennt, mit der der Dateiname erstellt wurde. Es ist ein bisschen außerhalb des Rahmens der Frage. Wählen Sie nicht das Beispiel aus, 'filename.csv.gz' ist auch ziemlich gültig.
FlipMcF
16

Im pathlib-Modul (verfügbar in Python 3.x) finden Sie einige großartige Dinge.

import pathlib
x = pathlib.PurePosixPath("C:\\Path\\To\\File\\myfile.txt").suffix
print(x)

# Output 
'.txt'
r3t40
quelle
14

Es ist zwar ein altes Thema, aber ich frage mich, warum es in diesem Fall keine Erwähnung einer sehr einfachen Python-API namens rpartition gibt:

Um die Erweiterung eines bestimmten absoluten Dateipfads zu erhalten, können Sie einfach Folgendes eingeben:

filepath.rpartition('.')[-1]

Beispiel:

path = '/home/jersey/remote/data/test.csv'
print path.rpartition('.')[-1]

wird dir geben: 'csv'

weiyixie
quelle
1
Für diejenigen, die mit der API nicht vertraut sind, gibt rpartition ein Tupel zurück : ("string before the right-most occurrence of the separator", "the separator itself", "the rest of the string"). Wenn kein Trennzeichen gefunden wird, lautet das zurückgegebene Tupel : ("", "", "the original string").
Nickolay
13

Einfach joinalles pathlib suffixes.

>>> x = 'file/path/archive.tar.gz'
>>> y = 'file/path/text.txt'
>>> ''.join(pathlib.Path(x).suffixes)
'.tar.gz'
>>> ''.join(pathlib.Path(y).suffixes)
'.txt'
Alex
quelle
12

Überrascht wurde dies noch nicht erwähnt:

import os
fn = '/some/path/a.tar.gz'

basename = os.path.basename(fn)  # os independent
Out[] a.tar.gz

base = basename.split('.')[0]
Out[] a

ext = '.'.join(basename.split('.')[1:])   # <-- main part

# if you want a leading '.', and if no result `None`:
ext = '.' + ext if ext else None
Out[] .tar.gz

Leistungen:

  • Funktioniert wie erwartet für alles, was mir einfällt
  • Keine Module
  • Kein Regex
  • Plattformübergreifend
  • Leicht erweiterbar (zB keine führenden Punkte für die Erweiterung, nur letzter Teil der Erweiterung)

Als Funktion:

def get_extension(filename):
    basename = os.path.basename(filename)  # os independent
    ext = '.'.join(basename.split('.')[1:])
    return '.' + ext if ext else None
PascalVKooten
quelle
1
Dies führt zu einer Ausnahme, wenn die Datei keine Erweiterung hat.
Thiruvenkadam
4
Diese Antwort ignoriert eine Variante absolut, wenn ein Dateiname viele Punkte im Namen enthält. Beispiel get_extension ('cmocka-1.1.0.tar.xz') => '.1.0.tar.xz' - falsch.
PADYMKO
@PADYMKO, IMHO sollte man keine Dateinamen mit Punkt als Teil des Dateinamens erstellen. Der obige Code soll nicht zu 'tar.xz' führen
Douwe van der Leest
2
Wechseln Sie einfach zu [-1]dann.
PascalVKooten
11

Sie können ein splitauf einem verwenden filename:

f_extns = filename.split(".")
print ("The extension of the file is : " + repr(f_extns[-1]))

Dies erfordert keine zusätzliche Bibliothek

Soheshdoshi
quelle
10
filename='ext.tar.gz'
extension = filename[filename.rfind('.'):]
Aufenthaltszeit
quelle
2
Dies führt dazu, dass das letzte Zeichen filenamezurückgegeben wird, wenn der Dateiname überhaupt keine hat .. Dies liegt daran, dass rfindzurückgegeben wird, -1wenn die Zeichenfolge nicht gefunden wird.
Mattst
6

Dies ist eine direkte Zeichenfolgendarstellungstechnik: Ich sehe viele erwähnte Lösungen, aber ich denke, die meisten betrachten Split. Split tut dies jedoch bei jedem Auftreten von "." . Was Sie lieber suchen, ist Partition.

string = "folder/to_path/filename.ext"
extension = string.rpartition(".")[-1]
Kenstars
quelle
2
Die Partition wurde bereits von @weiyixie vorgeschlagen .
Nickolay
5

Eine andere Lösung mit Rechtsaufteilung:

# to get extension only

s = 'test.ext'

if '.' in s: ext = s.rsplit('.', 1)[1]

# or, to get file name and extension

def split_filepath(s):
    """
    get filename and extension from filepath 
    filepath -> (filename, extension)
    """
    if not '.' in s: return (s, '')
    r = s.rsplit('.', 1)
    return (r[0], r[1])
Arnaldo P. Figueira Figueira
quelle
5

Auch diese Frage ist bereits beantwortet. Ich würde die Lösung in Regex hinzufügen.

>>> import re
>>> file_suffix = ".*(\..*)"
>>> result = re.search(file_suffix, "somefile.ext")
>>> result.group(1)
'.ext'
Micha
quelle
1
Oder \.[0-9a-z]+$wie in diesem Beitrag .
pault
2

Ein echter Einzeiler, wenn Sie Regex mögen. Und es spielt keine Rolle, auch wenn Sie zusätzliche "." mitten drin

import re

file_ext = re.search(r"\.([^.]+)$", filename).group(1)

Das Ergebnis finden Sie hier : Klicken Sie hier

Victor Wang
quelle
0

Dies ist die einfachste Methode , um sowohl Dateiname als auch Erweiterung in nur einer Zeile abzurufen .

fName, ext = 'C:/folder name/Flower.jpeg'.split('/')[-1].split('.')

>>> print(fName)
Flower
>>> print(ext)
jpeg

Im Gegensatz zu anderen Lösungen müssen Sie hierfür kein Paket importieren.

Ripon Kumar Saha
quelle
2
Dies funktioniert nicht für alle Dateien oder Typen, zum Beispiel 'archive.tar.gz
studioj
0

Zum Spaß ... sammle einfach die Erweiterungen in einem Diktat und verfolge sie alle in einem Ordner. Dann ziehen Sie einfach die gewünschten Erweiterungen.

import os

search = {}

for f in os.listdir(os.getcwd()):
    fn, fe = os.path.splitext(f)
    try:
        search[fe].append(f)
    except:
        search[fe]=[f,]

extensions = ('.png','.jpg')
for ex in extensions:
    found = search.get(ex,'')
    if found:
        print(found)
eatmeimadanish
quelle
Das ist eine schreckliche Idee. Ihr Code bricht für jede Dateierweiterung ab, die Sie zuvor noch nicht hinzugefügt haben!
Robert
0

Versuche dies:

files = ['file.jpeg','file.tar.gz','file.png','file.foo.bar','file.etc']
pen_ext = ['foo', 'tar', 'bar', 'etc']

for file in files: #1
    if (file.split(".")[-2] in pen_ext): #2
        ext =  file.split(".")[-2]+"."+file.split(".")[-1]#3
    else:
        ext = file.split(".")[-1] #4
    print (ext) #5
  1. Holen Sie sich alle Dateinamen in die Liste
  2. Teilen Sie den Dateinamen und überprüfen Sie die vorletzte Erweiterung. Befindet sie sich in der Liste pen_ext oder nicht?
  3. Wenn ja, verbinden Sie es mit der letzten Erweiterung und legen Sie es als Dateierweiterung fest
  4. Wenn nicht, geben Sie einfach die letzte Erweiterung als Dateierweiterung ein
  5. und dann schau es dir an
Ibnul Husainan
quelle
1
Dies bricht für eine Reihe von Sonderfällen. Siehe die akzeptierte Antwort. Es erfindet das Rad neu, nur auf fehlerhafte Weise.
Robert
Ich habe meine Antwort aktualisiert
Ibnul Husainan
Hallo! Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten.
Brian
@ Brian so?
Ibnul Husainan
Du machst es nur noch schlimmer und brichst es auf neue Weise. foo.tarist ein gültiger Dateiname. Was passiert, wenn ich das auf deinen Code werfe? Was ist mit .bashrcoder foo? Dafür gibt es aus einem bestimmten Grund eine Bibliotheksfunktion ...
Robert
-2
# try this, it works for anything, any length of extension
# e.g www.google.com/downloads/file1.gz.rs -> .gz.rs

import os.path

class LinkChecker:

    @staticmethod
    def get_link_extension(link: str)->str:
        if link is None or link == "":
            return ""
        else:
            paths = os.path.splitext(link)
            ext = paths[1]
            new_link = paths[0]
            if ext != "":
                return LinkChecker.get_link_extension(new_link) + ext
            else:
                return ""
DragonX
quelle
-3
def NewFileName(fichier):
    cpt = 0
    fic , *ext =  fichier.split('.')
    ext = '.'.join(ext)
    while os.path.isfile(fichier):
        cpt += 1
        fichier = '{0}-({1}).{2}'.format(fic, cpt, ext)
    return fichier
user5535053
quelle
-5
name_only=file_name[:filename.index(".")

Dadurch erhalten Sie den Dateinamen bis zum ersten ".", Was am häufigsten vorkommt.

Wookie
quelle
1
Erstens braucht er nicht den Namen, sondern die Erweiterung. Zweitens, selbst wenn er einen Namen brauchen würde, wäre es falsch durch Dateien wie:file.name.ext
ya_dimon
Wie von @ya_dimon erwähnt, funktioniert dies nicht für Dateinamen mit Punkten. Außerdem braucht er die Erweiterung!
Umar Dastgir