แยกส่วนขยายจากชื่อไฟล์ใน Python


คำตอบ:


1990

ใช่. ใช้os.path.splitext(ดูเอกสาร Python 2.XหรือเอกสารPython 3.X ):

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

ไม่เหมือนกับความพยายามในการแยกสตริงด้วยตนเองส่วนใหญ่os.path.splitextจะถือว่า/a/b.c/dเป็นไม่มีส่วนขยายอย่างถูกต้องแทนที่จะมีส่วนขยาย.c/dและจะถือว่า.bashrcไม่มีส่วนขยายแทนที่จะมีส่วนขยาย.bashrc:

>>> os.path.splitext('/a/b.c/d')
('/a/b.c/d', '')
>>> os.path.splitext('.bashrc')
('.bashrc', '')

15
การใช้งานของbasenameที่นี่สับสนเล็กน้อยตั้งแต่os.path.basename("/path/to/somefile.ext")กลับมา"somefile.ext"
Jiaaro

17
จะไม่endswith()เป็นแบบพกพาและ pythonic เพิ่มเติมหรือไม่
Sebastian Mach

79
@ klingt.net ในกรณีนี้.asdเป็นส่วนเสริมจริงๆ !! หากคุณคิดว่ามันfoo.tar.gzเป็นไฟล์บีบอัด gzip ( .gz) ซึ่งเกิดขึ้นเป็นไฟล์ tar ( .tar) แต่เป็นไฟล์ gzipตั้งแต่แรก ฉันไม่คาดหวังให้ส่งคืนส่วนขยายแบบคู่เลย
nosklo

159
มาตรฐานหลามประชุมฟังก์ชั่นการตั้งชื่อเป็นที่น่ารำคาญจริงๆ - splittextเกือบทุกครั้งที่ผมมองอีกครั้งนี้ขึ้นมาผมว่ามันเป็นความผิดพลาดเป็นอยู่ หากพวกเขาก็จะทำอะไรที่มีความหมายการหยุดพักระหว่างส่วนของชื่อนี้ก็ต้องการจะง่ายมากที่จะรับรู้ว่ามันเป็นหรือsplitExt split_extแน่นอนฉันไม่สามารถเป็นคนเดียวที่ทำผิดนี้ได้?
ArtOfWarfare

9
@Vingtoft คุณไม่ได้พูดถึงเรื่อง FileStorage ของ werkzeug ในความคิดเห็นของคุณและคำถามนี้ไม่มีอะไรเกี่ยวกับสถานการณ์เฉพาะนั้น มีบางอย่างผิดปกติกับวิธีที่คุณส่งชื่อไฟล์ =>os.path.splitext('somefile.ext') ('somefile', '.ext')รู้สึกฟรีให้ตัวอย่างเคาน์เตอร์จริงโดยไม่ต้องอ้างอิงห้องสมุดบุคคลที่สาม
Gewthen

400
import os.path
extension = os.path.splitext(filename)[1]

15
จากความอยากรู้ว่าทำไมimport os.pathแทนfrom os import path?
kiswa

2
โอ้ฉันแค่สงสัยว่ามีเหตุผลเฉพาะอยู่เบื้องหลัง (นอกเหนือจากการประชุม) ฉันยังคงเรียนรู้ Python และต้องการเรียนรู้เพิ่มเติม!
kiswa

55
มันขึ้นอยู่กับว่าถ้าคุณใช้from os import pathชื่อpathนั้นจะถูกนำมาใช้ในขอบเขตของคุณแล้วคนอื่นที่ดูโค้ดอาจไม่ทราบทันทีว่าพา ธ นั้นเป็นพา ธ จากโมดูลระบบปฏิบัติการ ที่ไหนที่คุณใช้import os.pathมันจะเก็บไว้ในosเนมสเปซและทุกที่ที่คุณโทรออกคนจะรู้ว่ามันpath()มาจากosโมดูลทันที
dennmat

18
ฉันรู้ว่ามันไม่ได้มีความหมายแตกต่างกัน แต่ฉันพบว่าการก่อสร้างนั้น_, extension = os.path.splitext(filename)ดูดีกว่ามาก
Tim Gilbert

3
หากคุณต้องการให้ส่วนขยายเป็นส่วนหนึ่งของนิพจน์ที่ซับซ้อนยิ่งขึ้น [1] อาจมีประโยชน์มากกว่า: if check_for_gzip and os.path.splitext(filename)[1] == '.gz':
gerardw

239

ใหม่ในเวอร์ชัน 3.4

import pathlib

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

ฉันประหลาดใจที่ยังไม่มีใครพูดถึงpathlibมันpathlibเยี่ยมยอด!

หากคุณต้องการคำต่อท้ายทั้งหมด (เช่นถ้าคุณมี.tar.gz) .suffixesจะส่งคืนรายการของพวกเขา!


12
ตัวอย่างการรับ. tar.gz:''.join(pathlib.Path('somedir/file.tar.gz').suffixes)
3780389

คำตอบที่ดี ฉันพบว่าบทช่วยสอนนี้มีประโยชน์มากกว่าเอกสารประกอบ: zetcode.com/python/pathlib
user118967

@ user3780389 จะไม่ใช่ "foo.bar.tar.gz" จะยังคงถูกต้อง ".tar.gz" หรือไม่ ถ้าเป็นเช่นนั้นข้อมูลโค้ดของคุณควรใช้.suffixes[-2:]เพื่อให้มั่นใจว่าจะได้รับ. tar.gz อย่างมากเท่านั้น
jeromej

111
import os.path
extension = os.path.splitext(filename)[1][1:]

เพื่อให้ได้ข้อความของส่วนขยายโดยไม่มีจุด


73

ตัวเลือกหนึ่งอาจแยกออกจากจุด:

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

ไม่มีข้อผิดพลาดเมื่อไฟล์ไม่มีส่วนขยาย:

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

แต่คุณต้องระวัง:

>>> "png".split(".")[-1]
'png'    # But file doesn't have an extension

4
สิ่งนี้จะทำให้คุณโมโหหากคุณกำลังอัปโหลด x.tar.gz
คิริลล์

19
ไม่จริง นามสกุลของไฟล์ชื่อ "x.tar.gz" คือ "gz" ไม่ใช่ "tar.gz" os.path.splitext ให้ ".os" เป็นส่วนขยายด้วย
Murat Çorlu

1
เราสามารถใช้ [1] แทน [-1] ฉันไม่สามารถเข้าใจ [-1] ด้วย split
user765443

7
[-1] เพื่อรับรายการสุดท้ายของรายการที่แยกด้วยจุด ตัวอย่าง:"my.file.name.js".split('.') => ['my','file','name','js]
Murat Çorlu

1
@BenjaminR เอาละคุณทำการเพิ่มประสิทธิภาพเกี่ยวกับรายการผลลัพธ์ ['file', 'tar', 'gz']กับ'file.tar.gz'.split('.') เทียบ กับ['file.tar', 'gz'] 'file.tar.gz'.rsplit('.', 1)ใช่อาจจะเป็น
Murat Çorlu

40

คุณควรคิดว่าทำไม JPG ถึงไม่ปรากฏในรายการของคุณ

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

19

วิธีการแก้ปัญหาใด ๆ ข้างต้นทำงาน แต่ใน linux ฉันได้พบว่ามีการขึ้นบรรทัดใหม่ในตอนท้ายของสตริงส่วนขยายซึ่งจะป้องกันไม่ให้ตรงกับการประสบความสำเร็จ เพิ่มstrip()วิธีการไปยังจุดสิ้นสุด ตัวอย่างเช่น:

import os.path
extension = os.path.splitext(filename)[1][1:].strip() 

1
เพื่อช่วยในการทำความเข้าใจของฉันคุณช่วยอธิบายเพิ่มเติมพฤติกรรมใดบ้างที่ดัชนี / ชิ้นป้องกันที่สอง? (เช่น[1:]ใน.splittext(filename)[1][1:]) - ขอบคุณล่วงหน้า
Samuel Harmer

1
คิดออกเอง: splittext()(ไม่เหมือนถ้าคุณแบ่งสตริงโดยใช้ '.') รวมถึง '.' ตัวอักษรในส่วนขยาย เพิ่มเติม[1:]กำจัดมัน
ซามูเอลฮาร์เมอร์

17

ด้วย splitext มีปัญหากับไฟล์ที่มีนามสกุลคู่ (เช่นfile.tar.gz, file.tar.bz2ฯลฯ .. )

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

แต่ควรจะ: .tar.gz

ทางออกที่เป็นไปได้อยู่ที่นี่


35
ไม่ควรเป็น. gz
Robert Siemer

1
ทำสองครั้งเพื่อรับส่วนขยาย 2 หรือไม่
maazza

1
@maazza อ๋อ gunzip somefile.tar.gz ชื่อไฟล์ที่ส่งออกคืออะไร?
FlipMcF

1
นี่คือเหตุผลที่เรามีส่วนขยาย 'tgz' ซึ่งหมายถึง: tar + gzip! : D
Nuno Aniceto

1
@peterhil ฉันไม่คิดว่าคุณต้องการให้สคริปต์ python ของคุณตระหนักถึงแอปพลิเคชันที่ใช้ในการสร้างชื่อไฟล์ มันค่อนข้างออกนอกขอบเขตของคำถาม อย่าเลือกตัวอย่างเช่น 'filename.csv.gz' ก็ใช้ได้เช่นกัน
FlipMcF

16

คุณสามารถค้นหาสิ่งที่ยอดเยี่ยมบางอย่างในโมดูล pathlib (มีให้ใน python 3.x)

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

# Output 
'.txt'

14

แม้ว่าจะเป็นหัวข้อเก่า แต่ฉันสงสัยว่าทำไมไม่มีใครพูดถึง api ง่าย ๆ ของงูใหญ่ที่เรียกว่า rpartition ในกรณีนี้:

ในการรับส่วนขยายของไฟล์ที่ระบุพา ธ สัมบูรณ์คุณสามารถพิมพ์:

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

ตัวอย่าง:

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

จะให้คุณ: 'csv'


1
สำหรับผู้ที่ไม่คุ้นเคยกับ API rpartitionส่งกลับ tuple ("string before the right-most occurrence of the separator", "the separator itself", "the rest of the string")นี้: หากมีตัวคั่นไม่พบ tuple ("", "", "the original string")ที่กลับมาจะได้รับ:
Nickolay

13

เพียงแค่ทุกคนjoinpathlib 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'

12

แปลกใจที่สิ่งนี้ยังไม่ได้กล่าวถึง:

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

ประโยชน์ที่ได้รับ:

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

ฟังก์ชั่น:

def get_extension(filename):
    basename = os.path.basename(filename)  # os independent
    ext = '.'.join(basename.split('.')[1:])
    return '.' + ext if ext else None

1
สิ่งนี้ส่งผลให้เกิดข้อยกเว้นเมื่อไฟล์ไม่มีส่วนขยายใด ๆ
thiruvenkadam

4
คำตอบนี้ไม่สนใจตัวแปรถ้าชื่อไฟล์มีหลายจุดในชื่อ ตัวอย่าง get_extension ('cmocka-1.1.0.tar.xz') => '.1.0.tar.xz' - ผิด
PADYMKO

@PADYMKO, IMHO หนึ่งไม่ควรสร้างชื่อไฟล์ที่มีการหยุดเต็มรูปแบบเป็นส่วนหนึ่งของชื่อไฟล์ โค้ดด้านบนไม่ควรส่งผลให้ 'tar.xz'
Douwe van der Leest

2
การเปลี่ยนแปลงเพียง[-1]แล้ว
PascalVKooten

11

คุณสามารถใช้splita filename:

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

สิ่งนี้ไม่ต้องการไลบรารีเพิ่มเติม


10
filename='ext.tar.gz'
extension = filename[filename.rfind('.'):]

2
ส่งผลให้อักขระตัวสุดท้ายของfilenameการถูกส่งคืนถ้าชื่อไฟล์ไม่มี.เลย นี่เป็นเพราะrfindส่งคืน-1หากไม่พบสตริง
mattst

6

นี่เป็นเทคนิคการนำเสนอสตริงโดยตรง: ฉันเห็นวิธีแก้ปัญหามากมายที่กล่าวถึง แต่ฉันคิดว่าส่วนใหญ่มองแยก แยกได้อย่างไรก็ตามไม่ว่าจะเกิดขึ้นที่ "." ทุกครั้ง . สิ่งที่คุณต้องการจะมองหาคือพาร์ติชัน

string = "folder/to_path/filename.ext"
extension = string.rpartition(".")[-1]

2
rpartition ก็บอกแล้วโดย@weiyixie
Nickolay

5

โซลูชันอื่นที่มีการแยกขวา:

# 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])

5

แม้แต่คำถามนี้ก็ได้รับคำตอบแล้วฉันก็จะเพิ่มโซลูชันใน Regex

>>> import re
>>> file_suffix = ".*(\..*)"
>>> result = re.search(file_suffix, "somefile.ext")
>>> result.group(1)
'.ext'

1
หรือ\.[0-9a-z]+$เหมือนในกระทู้นี้
pault


0

นี่คือวิธีที่ง่ายที่สุดที่จะได้รับทั้งชื่อไฟล์และส่วนต่อขยายในเพียงเส้นเดียว

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

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

ไม่เหมือนกับโซลูชันอื่น ๆ คุณไม่จำเป็นต้องนำเข้าแพ็คเกจใด ๆ


2
สิ่งนี้ใช้ไม่ได้กับไฟล์หรือประเภททั้งหมดเช่น 'archive.tar.gz
studioj

0

สำหรับ funsies ... เพียงรวบรวมนามสกุลใน dict และติดตามทั้งหมดในโฟลเดอร์ จากนั้นดึงส่วนขยายที่คุณต้องการ

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)

นั่นเป็นความคิดที่แย่มาก รหัสของคุณจะหยุดพักสำหรับนามสกุลไฟล์ใด ๆ ที่คุณไม่ได้เพิ่มไว้ก่อนหน้านี้!
Robert

0

ลองนี้:

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. รับชื่อไฟล์ทั้งหมดที่อยู่ในรายการ
  2. แยกชื่อไฟล์และตรวจสอบส่วนขยายสุดท้ายแล้วมันอยู่ในรายการ pen_ext หรือไม่
  3. ถ้าใช่แล้วเข้าร่วมกับนามสกุลสุดท้ายและตั้งเป็นนามสกุลของไฟล์
  4. ถ้าไม่ใช่ให้ใส่นามสกุลสุดท้ายเป็นนามสกุลไฟล์
  5. จากนั้นตรวจสอบ

1
นี่เป็นกรณีพิเศษ ดูคำตอบที่ยอมรับได้ มันสร้างใหม่ล้อในทางที่รถ
Robert

ฉันปรับปรุงคำตอบของฉัน
Ibnul Husainan

สวัสดี! แม้ว่ารหัสนี้อาจแก้ปัญหาได้รวมถึงคำอธิบายว่าทำไมและวิธีแก้ปัญหานี้จะช่วยปรับปรุงคุณภาพการโพสต์ของคุณได้อย่างไรและอาจส่งผลให้คะแนนมากขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่เพียงแค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
ไบรอัน

@Brian เช่นนั้น?
Ibnul Husainan

คุณแค่ทำให้มันแย่ลงทำลายมันในรูปแบบใหม่ foo.tarเป็นชื่อไฟล์ที่ถูกต้อง จะเกิดอะไรขึ้นถ้าฉันโยนรหัสของคุณลงไป สิ่งที่เกี่ยวกับ.bashrcหรือfoo? มีฟังก์ชั่นห้องสมุดสำหรับสิ่งนี้ด้วยเหตุผล ...
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 ""

-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

-5
name_only=file_name[:filename.index(".")

ซึ่งจะทำให้ชื่อไฟล์ของคุณเป็น "." อันแรกซึ่งจะเป็นชื่อสามัญที่สุด


1
ก่อนเขาไม่ต้องการชื่อ แต่ส่วนขยาย ประการที่สองแม้ว่าเขาจะต้องการชื่อก็จะผิดโดยไฟล์เช่น:file.name.ext
ya_dimon

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