Jak zamienić (lub usunąć) rozszerzenie z nazwy pliku w Pythonie?


113

Czy w Pythonie jest funkcja wbudowana, która zastąpiłaby (lub usunęłaby cokolwiek) rozszerzenie nazwy pliku (jeśli takie ma)?

Przykład:

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

W moim przykładzie: /home/user/somefile.txtstałoby się/home/user/somefile.jpg

Nie wiem, czy to ma znaczenie, ale potrzebuję tego dla modułu SCons, który piszę. (Więc może jest jakaś specyficzna funkcja SCons, której mogę użyć?)

Chciałbym coś czystego . Wykonanie prostej zamiany ciągu wszystkich wystąpień .txtw ciągu nie jest oczywiście czyste. (To się nie powiedzie, jeśli moja nazwa pliku to somefile.txt.txt.txt)



SCons umożliwia dostęp do bazy plików w ciągu akcji. Czy możesz opublikować swoją specyficzną logikę, która tego potrzebuje? Czy to dla akcji, nadajnika, skanera?
— bdbaddog

niektóre z nich wydają się już nie działać, ponieważ path zwraca PosixPath, a nie ciąg: p
— shigeta

Odpowiedzi:


146

Wypróbuj os.path.splitext , powinien zrobić to, co chcesz.

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

15
@ S.Lott: Wierz mi lub nie. Ale to zrobiłem. Zawsze to robię. Być może z niewłaściwymi warunkami.
— ereOn

@ereOn: Ponieważ twoje pytanie zawiera prawie takie same sformułowania, jestem trochę zaskoczony, że go nie znalazłeś. Twoje pytanie zawiera 5 słów - z rzędu - które dokładnie pasują.
— S.Lott

Dodaj nową nazwę tylko razem z os.path.join, aby wyglądała na czystą.
— Tony Veijalainen

4
@Tony Veijalainen: Nie powinieneś używać os.path.join, ponieważ służy to do łączenia komponentów ścieżki z separatorem ścieżki specyficznym dla systemu operacyjnego. Na przykład print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')zwróci /home/user/somefile/.jpg, co nie jest pożądane.
— scottclowe,

@ S.Lott - 99 osób się prawa głosu tę odpowiedź dość wyraźnie oznacza ten post jest pomocny, nie ma potrzeby wszystkich kapitalizacji zawstydzanie
— JeffThompson

92

Rozwijając odpowiedź AnaPana, jak usunąć rozszerzenie za pomocą 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

1
Real Python ma dobry opis przykładowych przypadków użycia modułu pathlib
— Steven C. Howell

2
Ta odpowiedź jest moim typowym podejściem, ale wydaje się, że zawodzi, gdy masz wiele rozszerzeń plików. Na przykład pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))wyświetli 'data/foo.tar.jpg'. Przypuszczam, że możesz to zrobić pth.with_suffix('').with_suffix('.jpg'), ale jest to niezgrabne i musiałbyś dodać dowolnie długi łańcuch .with_suffix('')wywołań, aby poradzić sobie z dowolną liczbą kropek .w rozszerzeniu pliku ( trzeba przyznać, że więcej niż 2 to egzotyczny przypadek krawędzi).
— tel

@tel Możesz użyć whilepętli, aby rozwiązać ten problem:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
— dericke

Zobacz moją odpowiedź poniżej, aby znaleźć rozwiązanie problemu z wieloma rozszerzeniami.
— Michael Hall

33

Jak powiedział @jethro, splitextjest to zgrabny sposób na zrobienie tego. Ale w tym przypadku dość łatwo jest to podzielić samodzielnie, ponieważ rozszerzenie musi być częścią nazwy pliku znajdującą się po ostatnim okresie:

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

rsplitMówi Python wykonać szpagat ciągów zaczynając od prawej strony napisu, a 1mówi się wykonywać co najwyżej jeden split (tak że np 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Ponieważ rsplitzawsze zwróci niepustą tablicę, możemy bezpiecznie zindeksować 0do niej, aby uzyskać nazwę pliku bez rozszerzenia.


8
Zauważ, że użycie rsplitspowoduje różne wyniki dla plików, które zaczynają się od kropki i nie mają innego rozszerzenia (jak np .bashrc. Pliki ukryte w Linuksie ). os.path.splitextzwraca dla nich puste rozszerzenie, ale użycie rsplitpotraktuje całą nazwę pliku jako rozszerzenie.
— Florian Brucker,

4
Daje to również nieoczekiwane wyniki dla nazwy pliku/home/john.johnson/somefile
— Will Manley

7

Preferuję następujące jednoliniowe podejście przy użyciu str.rsplit () :

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

Przykład:

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

2
To się nie powiedzie, jeśli plik nie ma rozszerzenia, a użytkownik to „john.doe”.
— Marek Jedliński

Czy wtedy wszyscy nie zawiodą?
— eatmeimadanish

6

Dla Pythona> = 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
Myślę, że podejście pathlib sugerowane przez JS. jest znacznie prostsze.
— h0b0

4

Obsługa wielu rozszerzeń

W przypadku, gdy masz wiele rozszerzeń, ta jedna linijka używa pathlibi str.replacedziała:

Usuń / zdejmij rozszerzenia

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

Wymień rozszerzenia

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

Jeśli chcesz również uzyskać pathlibobiekt wyjściowy, możesz oczywiście zawinąć linięPath()

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

Zawijanie tego wszystkiego w funkcję

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 ma do tego skrót: Path (). with_suffix ("") usunie rozszerzenie, a Path.with_suffix (". txt") zastąpi je.
— Levi

Poprawny. Ale usuwa tylko pierwsze rozszerzenie. Tak więc w powyższym przykładzie użycie with_suffixzamiast replaceusuwałoby tylko .gzzamiast. .tar.gz Moja odpowiedź miała być „ogólna”, ale jeśli spodziewasz się tylko jednego rozszerzenia, with_suffixbyłoby czystszym rozwiązaniem.
— Michael Hall

3

Innym sposobem jest użycie str.rpartition(sep)metody.

Na przykład:

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

new_filename = prefix + '.jpg'

print new_filename
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.