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.