จะแทนที่ (หรือถอด) ส่วนขยายจากชื่อไฟล์ใน Python ได้อย่างไร?


114

มีฟังก์ชันในตัวใน Python ที่จะแทนที่ (หรือลบอะไรก็ได้) ส่วนขยายของชื่อไฟล์ (ถ้ามี)?

ตัวอย่าง:

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

ในตัวอย่างของฉัน: /home/user/somefile.txtจะกลายเป็น/home/user/somefile.jpg

ฉันไม่รู้ว่ามันสำคัญหรือเปล่า แต่ฉันต้องการสิ่งนี้สำหรับโมดูล SCons ที่ฉันกำลังเขียนอยู่ (ดังนั้นอาจมีฟังก์ชันเฉพาะของ SCons ที่ฉันสามารถใช้ได้)

ฉันต้องการบางสิ่งบางอย่างที่สะอาด การเปลี่ยนสตริงอย่างง่ายของเหตุการณ์ทั้งหมด.txtภายในสตริงนั้นไม่สะอาดอย่างเห็นได้ชัด (สิ่งนี้จะล้มเหลวหากชื่อไฟล์ของฉันคือsomefile.txt.txt.txt)



SCons อนุญาตให้รับที่ฐานไฟล์ในสตริงการดำเนินการ คุณสามารถโพสต์ตรรกะเฉพาะของ scons ที่ต้องการสิ่งนี้ได้หรือไม่? นี่คือการกระทำตัวปล่อยสแกนเนอร์หรือไม่?
bdbaddog

บางส่วนดูเหมือนจะไม่ทำงานอีกต่อไปเนื่องจากเส้นทางส่งคืน PosixPath ไม่ใช่สตริง: p
shigeta

คำตอบ:


147

ลองos.path.splitextมันควรทำตามที่คุณต้องการ

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

15
@ S.Lott: เชื่อฉันหรือไม่ แต่ฉันทำ. ฉันทำอยู่เสมอ. บางทีอาจจะใช้ผิดเงื่อนไข
เมื่อ

@ereOn: เนื่องจากคำถามของคุณใช้วลีเดียวกันเกือบทั้งหมดฉันจึงแปลกใจเล็กน้อยที่คุณไม่พบมัน คำถามของคุณมี 5 คำ - ติดต่อกัน - ที่ตรงกัน
ล็อต

ใส่ชื่อใหม่ร่วมกับ os.path.join เท่านั้นเพื่อให้ดูสะอาดตา
Tony Veijalainen

4
@Tony Veijalainen: คุณไม่ควรใช้ os.path.join เพราะนั่นใช้สำหรับการเชื่อมต่อคอมโพเนนต์พา ธ กับตัวคั่นพา ธ เฉพาะ OS ตัวอย่างเช่นprint os.path.join(os.path.splitext('/home/user/somefile.txt')[0], '.jpg')จะกลับมา/home/user/somefile/.jpgซึ่งไม่เป็นที่ต้องการ
scottclowe

@ S.Lott - 99 คนโหวตคำตอบนี้ค่อนข้างชัดเจนหมายความว่าโพสต์นี้มีประโยชน์ไม่จำเป็นต้องมีการ
หลอกลวงทั้งหมด

92

ขยายคำตอบของ AnaPana วิธีการลบส่วนขยายโดยใช้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 มีตัวอย่างการใช้งานที่ดีของโมดูลpathlib
Steven C. Howell

2
คำตอบนี้เป็นแนวทางปกติของฉัน แต่ดูเหมือนว่าจะล้มเหลวเมื่อคุณมีนามสกุลไฟล์หลายไฟล์ ยกตัวอย่างเช่นออกจะpth = Path('data/foo.tar.gz'); print(pth.with_suffix('.jpg')) 'data/foo.tar.jpg'ฉันคิดว่าคุณสามารถทำได้pth.with_suffix('').with_suffix('.jpg')แต่มันไม่สะดวกและคุณจะต้องเพิ่ม.with_suffix('')สายการโทรที่ยาวโดยพลการเพื่อจัดการกับจำนวนจุดตามอำเภอใจ.ในนามสกุลไฟล์ (ยอมรับว่ามากกว่า 2 เป็นกรณีขอบที่แปลกใหม่)
โทร

@tel คุณสามารถใช้whileลูปเพื่อแก้ปัญหานั้นได้:pth = Path('data/foo.tar.gz'); while pth != pth.with_suffix(''): pth = pth.with_suffix(''); pth = pth.with_suffix('.jpg')
dericke

ดูคำตอบของฉันด้านล่างสำหรับวิธีแก้ปัญหาส่วนขยายหลายรายการ
Michael Hall

33

ดังที่ @jethro กล่าวว่าsplitextเป็นวิธีที่เรียบร้อยในการทำ แต่ในกรณีนี้มันค่อนข้างง่ายที่จะแยกมันเองเนื่องจากนามสกุลต้องเป็นส่วนหนึ่งของชื่อไฟล์ที่มาหลังจากช่วงเวลาสุดท้าย:

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

คำสั่งrsplitบอกให้ Python ทำการแยกสตริงโดยเริ่มจากด้านขวาของสตริงและ1บอกว่าให้ทำการแยกสูงสุดหนึ่งตัว (เช่น'foo.bar.baz'-> [ 'foo.bar', 'baz' ]) เนื่องจากrsplitจะส่งคืนอาร์เรย์ที่ไม่ว่างเปล่าเสมอเราจึงสามารถทำดัชนีได้อย่างปลอดภัย0เพื่อให้ได้ชื่อไฟล์ลบนามสกุล


8
โปรดทราบว่าการใช้rsplitจะทำให้ได้ผลลัพธ์ที่แตกต่างกันสำหรับไฟล์ที่ขึ้นต้นด้วยจุดและไม่มีนามสกุลอื่น ๆ (เช่นไฟล์ที่ซ่อนอยู่บน Linux เช่น.bashrc) os.path.splitextส่งคืนนามสกุลว่างสำหรับสิ่งเหล่านี้ แต่การใช้rsplitจะถือว่าชื่อไฟล์ทั้งหมดเป็นส่วนขยาย
Florian Brucker

4
สิ่งนี้จะให้ผลลัพธ์ที่ไม่คาดคิดสำหรับชื่อไฟล์/home/john.johnson/somefile
Will Manley

7

ฉันชอบแนวทางซับเดียวต่อไปนี้โดยใช้str.rsplit () :

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

ตัวอย่าง:

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

2
สิ่งนี้จะล้มเหลวหาก somefile ไม่มีส่วนขยายและผู้ใช้คือ 'john.doe'
Marek Jedliński

พวกเขาทั้งหมดจะไม่ล้มเหลวเหรอ?
eatmeimadanish

6

สำหรับ 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
ฉันคิดว่าแนวทางของ pathlib แนะนำโดย JS ง่ายกว่ามาก
h0b0

4

การจัดการส่วนขยายหลายรายการ

ในกรณีที่คุณมีส่วนขยายหลายรายการให้ใช้pathlibและใช้str.replaceงานได้:

ลบ / แถบส่วนขยาย

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

แทนที่ส่วนขยาย

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

หากคุณต้องการpathlibเอาท์พุทอ็อบเจ็กต์ด้วยคุณสามารถตัดบรรทัดเข้าได้อย่างชัดเจนPath()

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

รวมทุกอย่างไว้ในฟังก์ชัน

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 มีทางลัดสำหรับสิ่งนี้: Path (). with_suffix ("") จะลบส่วนขยายและ Path.with_suffix (". txt") จะแทนที่
Levi

แก้ไข. แต่จะลบส่วนขยายแรกเท่านั้น ดังนั้นในตัวอย่างข้างต้นใช้with_suffixแทนreplaceเท่านั้นที่จะลบ.gzแทน.tar.gz คำตอบของฉันก็ตั้งใจจะ "ทั่วไป" แต่ถ้าคุณเพียง แต่คาดว่าจะมีการขยายเดียวwith_suffixจะแก้ปัญหาการทำความสะอาด
Michael Hall

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.