Trích xuất phần mở rộng từ tên tệp trong Python


Câu trả lời:


1990

Đúng. Sử dụng os.path.splitext(xem tài liệu Python 2.X hoặc tài liệu Python 3.X ):

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

Không giống như hầu hết các nỗ lực tách chuỗi thủ công, os.path.splitextsẽ coi chính xác /a/b.c/dlà không có tiện ích mở rộng thay vì có tiện ích mở rộng .c/dvà nó sẽ coi .bashrclà không có tiện ích mở rộng thay vì có tiện ích mở rộng .bashrc:

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

15
việc sử dụng basenamecó một chút khó hiểu ở đây kể từ khi os.path.basename("/path/to/somefile.ext")trở lại"somefile.ext"
Jiaaro

17
sẽ không endswith()di động và pythonic hơn?
Sebastian Mach

79
@ klingt.net Vâng, trong trường hợp đó, .asdthực sự là phần mở rộng !! Nếu bạn nghĩ về nó, foo.tar.gzlà một tệp nén gzip ( .gz) xảy ra là một tệp tar ( .tar). Nhưng nó là một tập tin gzip ở vị trí đầu tiên. Tôi sẽ không mong đợi nó sẽ trả lại phần mở rộng kép.
nosklo

160
Quy ước đặt tên hàm Python tiêu chuẩn thực sự gây phiền nhiễu - hầu như mỗi lần tôi tìm lại cái này, tôi lại nhầm nó là splittext. Nếu họ chỉ cần làm bất cứ điều gì để biểu thị sự phá vỡ giữa các phần của tên này, sẽ dễ dàng hơn nhiều để nhận ra rằng đó là splitExthoặc split_ext. Chắc chắn tôi không thể là người duy nhất mắc lỗi này?
ArtOfWarfare 7/1/2015

9
@Vingtoft Bạn không đề cập gì về FileStorage của werkzeug trong bình luận của bạn và câu hỏi này không có gì về kịch bản cụ thể đó. Một cái gì đó có thể sai với cách bạn được thông qua tên tệp. os.path.splitext('somefile.ext')=> ('somefile', '.ext'). Hãy thoải mái cung cấp một ví dụ truy cập thực tế mà không cần tham khảo một số thư viện bên thứ ba.
Gewthen

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

15
Vì tò mò, tại sao import os.paththay vì from os import path?
kiswa

2
Ồ, tôi chỉ tự hỏi liệu có một lý do cụ thể đằng sau nó (ngoài quy ước). Tôi vẫn đang học Python và muốn tìm hiểu thêm!
kiswa

55
Nó thực sự phụ thuộc, nếu bạn sử dụng from os import paththì tên pathđược đưa lên trong phạm vi cục bộ của bạn, những người khác đang xem mã có thể không biết ngay đường dẫn đó là đường dẫn từ mô-đun os. Nếu bạn sử dụng import os.pathnó sẽ giữ nó trong oskhông gian tên và bất cứ nơi nào bạn thực hiện cuộc gọi, mọi người sẽ biết ngay path()từ osmô-đun.
dennmat

18
Tôi biết nó không khác biệt về mặt ngữ nghĩa, nhưng cá nhân tôi thấy công trình _, extension = os.path.splitext(filename)trông đẹp hơn nhiều.
Tim Gilbert

3
Nếu bạn muốn tiện ích mở rộng là một phần của biểu thức phức tạp hơn, [1] có thể hữu ích hơn: if check_for_gzip and os.path.splitext(filename)[1] == '.gz':
gerardw

239

Mới trong phiên bản 3.4.

import pathlib

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

Tôi ngạc nhiên không ai nhắc đến pathlib,pathlib thật tuyệt vời!

Nếu bạn cần tất cả các hậu tố (ví dụ nếu bạn có a .tar.gz), .suffixessẽ trả về một danh sách của chúng!


12
ví dụ để nhận .tar.gz:''.join(pathlib.Path('somedir/file.tar.gz').suffixes)
user3780389

Câu trả lời chính xác. Tôi thấy hướng dẫn này hữu ích hơn tài liệu: zetcode.com/python/pathlib
user118967

@ user3780389 Sẽ không phải là "foo.bar.tar.gz" vẫn là ".tar.gz" hợp lệ chứ? Nếu vậy, đoạn trích của bạn nên được sử dụng .suffixes[-2:]để đảm bảo chỉ nhận được .tar.gz.
jeromej

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

Để chỉ nhận văn bản của phần mở rộng, không có dấu chấm.


73

Một tùy chọn có thể được tách từ dấu chấm:

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

Không có lỗi khi tệp không có phần mở rộng:

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

Nhưng bạn phải cẩn thận:

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

4
Điều này sẽ gây khó chịu nếu bạn đang tải lên x.tar.gz
Kirill

19
Không thực sự. Phần mở rộng của tệp có tên "x.tar.gz" là "gz" chứ không phải "tar.gz". os.path.splitext cũng cung cấp ".os".
Murat Çorlu

1
chúng ta có thể sử dụng [1] thay vì [-1]. Tôi không thể hiểu [-1] bằng cách chia
user765443

7
[-1] để lấy mục cuối cùng của các mục được phân tách bằng dấu chấm. Ví dụ:"my.file.name.js".split('.') => ['my','file','name','js]
Murat orlu

1
@BenjaminR ah ok, bạn đang thực hiện tối ưu hóa về danh sách kết quả. ['file', 'tar', 'gz']với 'file.tar.gz'.split('.') vs ['file.tar', 'gz'] với 'file.tar.gz'.rsplit('.', 1). vâng, có thể
Murat Çorlu

40

đáng để thêm một mức thấp hơn trong đó để bạn không thấy mình thắc mắc tại sao JPG không hiển thị trong danh sách của bạn.

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

19

Bất kỳ giải pháp nào ở trên đều hoạt động, nhưng trên linux tôi đã thấy rằng có một dòng mới ở cuối chuỗi mở rộng sẽ ngăn các kết quả khớp thành công. Thêm strip()phương thức vào cuối. Ví dụ:

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

1
Để hỗ trợ sự hiểu biết của tôi, xin vui lòng bạn có thể giải thích hành vi bổ sung nào cho chỉ số thứ hai / người bảo vệ lát cắt chống lại? (tức là [1:]trong .splittext(filename)[1][1:]) - cảm ơn bạn trước
Samuel Harmer

1
Tự mình tìm ra nó: splittext()(không giống như nếu bạn tách một chuỗi bằng '.') Bao gồm '.' nhân vật trong phần mở rộng. Việc bổ sung [1:]được loại bỏ nó.
Samuel Harmer

17

Với splitext có những vấn đề với các tập tin với phần mở rộng gấp đôi (ví dụ file.tar.gz, file.tar.bz2, vv ..)

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

nhưng nên: .tar.gz

Các giải pháp có thể có ở đây


35
Không, nên là .gz
Robert Siemer

1
làm hai lần để có được 2 phần mở rộng?
maazza

1
@maazza vâng. gunzip somefile.tar.gz Tên tập tin đầu ra là gì?
FlipMcF

1
Đây là lý do tại sao chúng tôi có tiện ích mở rộng 'tgz' có nghĩa là: tar + gzip! : D
Nuno Aniceto

1
@peterhil Tôi không nghĩ bạn muốn tập lệnh python của bạn nhận thức được ứng dụng được sử dụng để tạo tên tệp. Đó là một chút ngoài phạm vi của câu hỏi. Đừng chọn ví dụ, 'filename.csv.gz' cũng khá hợp lệ.
FlipMcF

16

Bạn có thể tìm thấy một số công cụ tuyệt vời trong mô-đun pathlib (có sẵn trong python 3.x).

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

# Output 
'.txt'

14

Mặc dù đây là một chủ đề cũ, nhưng tôi tự hỏi tại sao không có đề cập đến một api rất đơn giản của con trăn được gọi là rpartition trong trường hợp này:

để có được phần mở rộng của một đường dẫn tuyệt đối của tệp đã cho, bạn chỉ cần gõ:

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

thí dụ:

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

sẽ cung cấp cho bạn: 'csv'


1
Đối với những người không quen thuộc với API, rpartition trả về một tuple : ("string before the right-most occurrence of the separator", "the separator itself", "the rest of the string"). Nếu không tìm thấy dấu phân cách, bộ dữ liệu được trả về sẽ là : ("", "", "the original string").
Nickolay

13

Chỉ cần jointất cả pathlib 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

Ngạc nhiên vì điều này chưa được đề cập:

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

Những lợi ích:

  • Hoạt động như mong đợi cho bất cứ điều gì tôi có thể nghĩ đến
  • Không có mô-đun
  • Không có regex
  • Đa nền tảng
  • Dễ dàng mở rộng (ví dụ: không có dấu chấm hàng đầu cho tiện ích mở rộng, chỉ phần cuối của tiện ích mở rộng)

Như chức năng:

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

1
Điều này dẫn đến một ngoại lệ khi tệp không có bất kỳ phần mở rộng nào.
thiruvenkadam

4
Câu trả lời này hoàn toàn bỏ qua một biến thể nếu tên tệp chứa nhiều điểm trong tên. Ví dụ get_extension ('cmocka-1.1.0.tar.xz') => '.1.0.tar.xz' - sai.
PADYMKO

@PADYMKO, IMHO không nên tạo tên tệp với các điểm dừng đầy đủ như một phần của tên tệp. Mã ở trên không được cho là dẫn đến 'tar.xz'
Douwe van der Leest

2
Chỉ cần thay đổi để [-1]sau đó.
PascalVKooten

11

Bạn có thể sử dụng một splittrên filename:

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

Điều này không cần thêm thư viện


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

2
Điều này dẫn đến char cuối cùng filenameđược trả về nếu tên tệp hoàn toàn không có .. Điều này là do rfindtrả về -1nếu không tìm thấy chuỗi.
mattst

6

Đây là một kỹ thuật biểu diễn chuỗi trực tiếp: Tôi thấy rất nhiều giải pháp được đề cập, nhưng tôi nghĩ hầu hết đang xem xét phân tách. Tuy nhiên, phân tách làm điều đó tại mọi lần xuất hiện của "." . Những gì bạn muốn tìm kiếm là phân vùng.

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

2
sự hợp tác đã được đề xuất bởi @weiyixie .
Nickolay

5

Một giải pháp khác với sự phân chia đúng:

# 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

Ngay cả câu hỏi này đã được trả lời, tôi sẽ thêm giải pháp vào Regex.

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

1
Hoặc \.[0-9a-z]+$như trong bài viết này .
pault

2

Một lót thực sự, nếu bạn thích regex. Và nó không quan trọng ngay cả khi bạn có thêm "." ở giữa

import re

file_ext = re.search(r"\.([^.]+)$", filename).group(1)

Xem ở đây để biết kết quả: Bấm vào đây


0

Đây là Phương pháp đơn giản nhất để có được cả Tên tệp & Tiện ích mở rộng chỉ trong một dòng .

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

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

Không giống như các giải pháp khác, bạn không cần nhập bất kỳ gói nào cho việc này.


2
điều này không hoạt động đối với tất cả các tệp hoặc loại ví dụ 'archive.tar.gz
studioj

0

Đối với các cuộc vui ... chỉ cần thu thập các tiện ích mở rộng trong một lệnh và theo dõi tất cả chúng trong một thư mục. Sau đó, chỉ cần kéo các phần mở rộng bạn muốn.

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)

Đó là một ý tưởng tồi tệ. Mã của bạn phá vỡ cho bất kỳ phần mở rộng tập tin mà bạn chưa thêm trước đây!
Robert

0

thử cái này:

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. lấy tất cả tên tập tin trong danh sách
  2. tách tên tệp và kiểm tra phần mở rộng áp chót, nó có trong danh sách pen_ext hay không?
  3. nếu có thì hãy nối nó với phần mở rộng cuối cùng và đặt nó làm phần mở rộng của tệp
  4. nếu không thì chỉ cần đặt phần mở rộng cuối cùng làm phần mở rộng của tệp
  5. và sau đó kiểm tra nó

1
Điều này phá vỡ cho một loạt các trường hợp đặc biệt. Xem câu trả lời được chấp nhận. Đó là phát minh lại bánh xe, chỉ trong một cách lỗi.
Robert

tôi đã cập nhật câu trả lời của mình
Ibnul Hushai

Xin chào! Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do giải quyết vấn đề này thực sự sẽ giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều lượt bình chọn hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định được áp dụng.
Brian

@Brian như thế?
Ibnul Hushai

Bạn chỉ làm cho nó tồi tệ hơn, phá vỡ nó theo những cách mới. foo.tarlà tên tệp hợp lệ. Điều gì xảy ra nếu tôi ném mã đó vào mã của bạn? Thế còn .bashrchay foo? Có một chức năng thư viện cho điều này vì một lý do ...
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(".")

Điều đó sẽ cung cấp cho bạn tên tệp cho đến "." Đầu tiên, là tên phổ biến nhất.


1
Đầu tiên, anh ta không cần tên, mà là phần mở rộng. Thứ hai, ngay cả khi anh ta cần tên, nó sẽ bị sai bởi các tệp như:file.name.ext
ya_dimon

Như được đề cập bởi @ya_dimon, điều này sẽ không hoạt động đối với tên tệp có dấu chấm. Thêm vào đó, anh ta cần gia hạn!
Umar Dastgir
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.