Làm cách nào để thay thế (hoặc tách) một phần mở rộng khỏi tên tệp bằng Python?


112

Có một hàm tích hợp sẵn trong Python sẽ thay thế (hoặc loại bỏ, bất cứ điều gì) phần mở rộng của tên tệp (nếu nó có)?

Thí dụ:

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

Trong ví dụ của tôi: /home/user/somefile.txtsẽ trở thành/home/user/somefile.jpg

Tôi không biết nó có quan trọng không, nhưng tôi cần cái này cho một mô-đun SCons mà tôi đang viết. (Vì vậy, có lẽ có một số chức năng SCons cụ thể mà tôi có thể sử dụng?)

Tôi muốn một cái gì đó sạch sẽ . Thực hiện thay thế chuỗi đơn giản của tất cả các lần xuất hiện .txttrong chuỗi rõ ràng là không sạch. (Điều này sẽ không thành công nếu tên tệp của tôi là somefile.txt.txt.txt)



SCons cho phép truy cập tệp cơ sở trong một chuỗi hành động. Bạn có thể đăng logic cụ thể scons của bạn cần điều này không? Đây có phải là hành động, bộ phát, máy quét không?
bdbaddog

một số điều này dường như không làm việc nữa như lợi nhuận con đường một PosixPath không phải là một chuỗi: p
Shigeta

Câu trả lời:


146

Hãy thử os.path.splitext nó sẽ làm những gì bạn muốn.

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

15
@ S.Lott: Tin tôi hay không. Nhưng tôi đã làm. Tôi luôn luôn làm. Có lẽ với các điều khoản sai.
vào

@ereOn: Vì câu hỏi của bạn sử dụng gần như cùng một cụm từ chính xác, tôi hơi ngạc nhiên khi bạn không tìm thấy nó. Câu hỏi của bạn có 5 từ - liên tiếp - khớp chính xác.
S.Lott

Chỉ đặt tên mới cùng với os.path.join để trông sạch sẽ.
Tony Veijalainen

4
@Tony Veijalainen: Bạn không nên sử dụng os.path.join vì đó là để nối các thành phần đường dẫn với dấu phân tách đường dẫn dành riêng cho hệ điều hành. Ví dụ, print os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')sẽ trở lại /home/user/somefile/.jpg, mà không phải là mong muốn.
scottclowe

@ S.Lott - 99 người bỏ phiếu cho câu trả lời này khá rõ ràng có nghĩa là bài đăng này hữu ích, không cần phải nói xấu
JeffThompson

91

Mở rộng câu trả lời của AnaPana, cách xóa tiện ích mở rộng bằng cách sử dụng 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
Bất Python có một tốt write-up các trường hợp ví dụ sử dụng các mô-đun pathlib: realpython.com/python-pathlib
Steven C. Howell

2
Câu trả lời này là cách tiếp cận điển hình của tôi, nhưng nó dường như không thành công khi bạn có nhiều phần mở rộng tệp. Ví dụ, pth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg'))sẽ xuất ra 'data/foo.tar.jpg'. Tôi cho rằng bạn có thể làm được pth.with_suffix('').with_suffix('.jpg'), nhưng điều đó thật khó hiểu và bạn sẽ cần thêm một chuỗi lệnh dài tùy ý .with_suffix('')để xử lý số lượng dấu chấm tùy ý .trong phần mở rộng tệp (phải thừa nhận rằng nhiều hơn 2 là một trường hợp cạnh kỳ lạ).
điện thoại

@tel Bạn có thể sử dụng một whilevòng lặp để giải quyết điều đó:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
dericke

Xem câu trả lời của tôi bên dưới để biết giải pháp cho vấn đề nhiều tiện ích.
Michael Hall

33

Như @jethro đã nói, đây splitextlà một cách làm gọn gàng. Nhưng trong trường hợp này, khá dễ dàng để tự tách nó ra, vì phần mở rộng phải là một phần của tên tệp sau dấu chấm cuối cùng:

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

Lệnh rsplitcho Python thực hiện tách chuỗi bắt đầu từ bên phải của chuỗi và1 thực hiện nhiều nhất một lần tách (ví dụ: 'foo.bar.baz'-> [ 'foo.bar', 'baz' ]). Vì rsplitsẽ luôn trả về một mảng không trống, chúng tôi có thể lập chỉ mục an toàn 0vào đó để lấy tên tệp trừ đi phần mở rộng.


8
Lưu ý rằng việc sử dụng rsplitsẽ dẫn đến các kết quả khác nhau đối với các tệp bắt đầu bằng dấu chấm và không có phần mở rộng nào khác (ví dụ như tệp ẩn trên Linux .bashrc). os.path.splitexttrả về một phần mở rộng trống cho những phần này, nhưng việc sử dụng rsplitsẽ coi toàn bộ tên tệp là phần mở rộng.
Florian Brucker

4
Điều này cũng sẽ cho kết quả bất ngờ cho tên tập tin/home/john.johnson/somefile
Will Manley

7

Tôi thích cách tiếp cận một lớp sau bằng cách sử dụng str.rsplit () :

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

Thí dụ:

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

2
Điều này không thành công nếu somefile không có phần mở rộng và người dùng là 'john.doe'.
Marek Jedliński

Không phải tất cả họ sẽ thất bại sau đó?
eatmeimadanish

6

Đối với 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
Tôi nghĩ cách tiếp cận pathlib do JS đề xuất. đơn giản hơn nhiều.
h0b0

4

Xử lý nhiều tiện ích mở rộng

Trong trường hợp bạn có nhiều tiện ích mở rộng, một lớp lót này sẽ sử dụng pathlibstr.replacehoạt động:

Xóa / tách phần mở rộng

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

Thay thế phần mở rộng

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

Nếu bạn cũng muốn có một pathlibđầu ra đối tượng thì rõ ràng bạn có thể quấn dòng vàoPath()

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

Gói gọn tất cả trong một hàm

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 có một phím tắt cho điều này: Path (). with_suffix ("") sẽ xóa một phần mở rộng và Path.with_suffix (". txt") sẽ thay thế nó.
Levi

Chính xác. Nhưng nó chỉ loại bỏ phần mở rộng đầu tiên. Vì vậy, trong ví dụ trên, sử dụng with_suffixthay vì replacesẽ chỉ loại bỏ .gzthay vì .tar.gz Câu trả lời của tôi được dự định là "chung chung", nhưng nếu bạn chỉ mong đợi một phần mở rộng duy nhất, with_suffixsẽ là một giải pháp rõ ràng hơn.
Michael Hall

3

Một cách khác để làm là sử dụng str.rpartition(sep)phương pháp.

Ví dụ:

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

new_filename = prefix + '.jpg'

print new_filename
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.