Làm cách nào để xóa chuỗi con khỏi cuối chuỗi trong Python?


382

Tôi có đoạn mã sau:

url = 'abcdc.com'
print(url.strip('.com'))

Tôi mong đợi: abcdc

Tôi đã nhận: abcd

Bây giờ tôi làm

url.rsplit('.com', 1)

Có cách nào tốt hơn?


6
dải dải các ký tự được cung cấp từ cả hai đầu của chuỗi, trong trường hợp của bạn, dải ".", "c", "o" và "m".
truppo

6
Nó cũng sẽ loại bỏ các ký tự đó từ phía trước của chuỗi. Nếu bạn chỉ muốn xóa nó từ cuối, hãy sử dụng rstrip ()
Andre Miller

42
Vâng. str.strip không làm những gì bạn nghĩ nó làm. str.strip loại bỏ bất kỳ ký tự nào được chỉ định từ đầu và cuối chuỗi. Vì vậy, "acbacda" .strip ("quảng cáo") cho 'cbac'; a ở đầu và da ở cuối bị tước. Chúc mừng.
scvalex

2
Thêm vào đó, điều này loại bỏ các ký tự theo bất kỳ thứ tự nào : "site.ocm"> "trang web".
Eric O Lebigot

1
@scvalex, wow chỉ nhận ra điều này đã sử dụng nó theo cách đó từ lâu - thật nguy hiểm vì mã thường xảy ra để hoạt động
Flash

Câu trả lời:


556

stripkhông có nghĩa là "loại bỏ chuỗi con này". x.strip(y)coi ynhư một tập hợp các ký tự và loại bỏ bất kỳ ký tự nào trong tập hợp đó từ cuối của x.

Thay vào đó, bạn có thể sử dụng endswithvà cắt:

url = 'abcdc.com'
if url.endswith('.com'):
    url = url[:-4]

Hoặc sử dụng các biểu thức thông thường :

import re
url = 'abcdc.com'
url = re.sub('\.com$', '', url)

4
Vâng, bản thân tôi nghĩ rằng ví dụ đầu tiên, với bài kiểm tra endswith (), sẽ là ví dụ tốt hơn; regex một sẽ liên quan đến một số hình phạt hiệu suất (phân tích regex, v.v.). Tôi sẽ không đi với rsplit (), nhưng đó là vì tôi không biết chính xác những gì bạn đang cố gắng đạt được. Tôi nghĩ rằng nó sẽ xóa .com nếu và chỉ khi nó xuất hiện ở cuối url? Giải pháp rsplit sẽ gây rắc rối cho bạn nếu bạn sử dụng nó trên các tên miền như 'www.commIALthingie.co.uk'
Steef

13
url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
Burhan Khalid

1
Điều gì xảy ra nếu tôi viết EXAMLPLE.COMtên miền không phân biệt chữ hoa chữ thường. (Đây là phiếu bầu cho giải pháp regex)
Jasen

3
Nó không phải là viết lại, rsplit()giải pháp không có hành vi tương tự như endswith()khi chuỗi ban đầu không có chuỗi con ở cuối, nhưng ở đâu đó ở giữa. Ví dụ: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"nhưng"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef

1
Cú pháp s[:-n]có một cảnh báo: vì n = 0, điều này không trả về chuỗi có các ký tự 0 cuối cùng bị cắt, nhưng thay vào đó là chuỗi trống.
BlenderBender

90

Nếu bạn chắc chắn rằng chuỗi chỉ xuất hiện ở cuối, thì cách đơn giản nhất sẽ là sử dụng 'thay thế':

url = 'abcdc.com'
print(url.replace('.com',''))

56
Điều đó cũng sẽ thay thế url như thế nào www.computerhope.com. làm một kiểm tra với endswith()và sẽ ổn.
ghostdog74

72
"www.computerhope.com".endswith(".com")là sự thật, nó vẫn sẽ phá vỡ!

1
"Nếu bạn chắc chắn rằng chuỗi chỉ xuất hiện ở cuối", bạn có nghĩa là "Nếu bạn chắc chắn rằng chuỗi con chỉ xuất hiện một lần"? thay thế dường như cũng hoạt động khi chuỗi con ở giữa, nhưng như các bình luận khác cho thấy nó sẽ thay thế bất kỳ sự xuất hiện nào của chuỗi con, tại sao cuối cùng tôi không hiểu
idclev 463035818

49
def strip_end(text, suffix):
    if not text.endswith(suffix):
        return text
    return text[:len(text)-len(suffix)]

4
Nếu bạn biết rằng hậu tố không trống (như khi nó là hằng số) thì: return text [: - len (hậu tố)]
MarcH

4
Cảm ơn. Dòng cuối cùng có thể được rút ngắn:return text[:-len(suffix)]
Jabba

3
@Jabba: Đáng buồn thay, điều đó sẽ không làm việc cho các hậu tố trống, như fuenfundachtzig đã đề cập.
yairchu

46

Vì có vẻ như chưa có ai chỉ ra điều này:

url = "www.example.com"
new_url = url[:url.rfind(".")]

Điều này sẽ hiệu quả hơn các phương thức sử dụng split()vì không có đối tượng danh sách mới nào được tạo và giải pháp này hoạt động cho các chuỗi có nhiều dấu chấm.


Wow đó là một mẹo hay. Tôi không thể làm điều này thất bại nhưng tôi cũng đã có một thời gian khó khăn để có thể nghĩ ra những cách này có thể thất bại. Tôi thích nó nhưng nó rất "kỳ diệu", khó có thể biết điều này làm gì khi chỉ nhìn vào nó. Tôi đã phải xử lý tinh thần từng phần của dòng để "có được".
DevPlayer

14
Điều này không thành công nếu chuỗi tìm kiếm KHÔNG có mặt và thay vào đó nó xóa nhầm ký tự cuối cùng.
robbat2

25

Phụ thuộc vào những gì bạn biết về url của mình và chính xác những gì bạn đang cố gắng làm. Nếu bạn biết rằng nó sẽ luôn kết thúc bằng '.com' (hoặc '.net' hoặc '.org') thì

 url=url[:-4]

là giải pháp nhanh nhất. Nếu đó là một URL tổng quát hơn thì có lẽ bạn nên xem xét thư viện urlparse đi kèm với python.

Mặt khác, nếu bạn muốn xóa mọi thứ sau trận chung kết '.' trong một chuỗi

url.rsplit('.',1)[0]

sẽ làm việc. Hoặc nếu bạn muốn chỉ muốn mọi thứ lên đến đầu tiên '.' vậy hãy thử đi

url.split('.',1)[0]

16

Nếu bạn biết đó là một phần mở rộng, thì

url = 'abcdc.com'
...
url.rsplit('.', 1)[0]  # split at '.', starting from the right, maximum 1 split

Điều này hoạt động tốt như nhau với abcdc.comhoặc www.abcdc.comhoặc abcdc.[anything]có thể mở rộng hơn.


12

Trong một dòng:

text if not text.endswith(suffix) or len(suffix) == 0 else text[:-len(suffix)]

8

Thế còn url[:-4]?


Có vẻ như hầu như được đảm bảo để dẫn đến một lỗi khi bạn bị tấn công bằng một .cahoặc một .co.ukurl.
Peter

7

Đối với các url (vì nó dường như là một phần của chủ đề theo ví dụ đã cho), người ta có thể làm một cái gì đó như thế này:

import os
url = 'http://www.stackoverflow.com'
name,ext = os.path.splitext(url)
print (name, ext)

#Or:
ext = '.'+url.split('.')[-1]
name = url[:-len(ext)]
print (name, ext)

Cả hai sẽ xuất ra: ('http://www.stackoverflow', '.com')

Điều này cũng có thể được kết hợp với str.endswith(suffix)nếu bạn chỉ cần tách ".com" hoặc bất cứ điều gì cụ thể.


5

url.rsplit ('. com', 1)

không hoàn toàn đúng

Những gì bạn thực sự cần phải viết là

url.rsplit('.com', 1)[0]

và nó trông khá ngắn gọn IMHO.

Tuy nhiên, sở thích cá nhân của tôi là tùy chọn này vì nó chỉ sử dụng một tham số:

url.rpartition('.com')[0]

1
Phân vùng +1 được ưu tiên khi chỉ cần một lần phân tách vì nó luôn trả về câu trả lời, IndexError sẽ không xảy ra.
Gringo Suave


2

Nếu bạn cần tước một số đầu của chuỗi nếu nó tồn tại thì không làm gì cả. Giải pháp tốt nhất của tôi. Bạn có thể sẽ muốn sử dụng một trong 2 triển khai đầu tiên tuy nhiên tôi đã bao gồm lần thứ 3 để hoàn thiện.

Đối với một hậu tố không đổi:

def remove_suffix(v, s):
    return v[:-len(s) if v.endswith(s) else v
remove_suffix("abc.com", ".com") == 'abc'
remove_suffix("abc", ".com") == 'abc'

Đối với một regex:

def remove_suffix_compile(suffix_pattern):
    r = re.compile(f"(.*?)({suffix_pattern})?$")
    return lambda v: r.match(v)[1]
remove_domain = remove_suffix_compile(r"\.[a-zA-Z0-9]{3,}")
remove_domain("abc.com") == "abc"
remove_domain("sub.abc.net") == "sub.abc"
remove_domain("abc.") == "abc."
remove_domain("abc") == "abc"

Đối với một tập hợp các hậu tố không đổi, cách nhanh nhất không có triệu chứng cho một số lượng lớn các cuộc gọi:

def remove_suffix_preprocess(*suffixes):
    suffixes = set(suffixes)
    try:
        suffixes.remove('')
    except KeyError:
        pass

    def helper(suffixes, pos):
        if len(suffixes) == 1:
            suf = suffixes[0]
            l = -len(suf)
            ls = slice(0, l)
            return lambda v: v[ls] if v.endswith(suf) else v
        si = iter(suffixes)
        ml = len(next(si))
        exact = False
        for suf in si:
            l = len(suf)
            if -l == pos:
                exact = True
            else:
                ml = min(len(suf), ml)
        ml = -ml
        suffix_dict = {}
        for suf in suffixes:
            sub = suf[ml:pos]
            if sub in suffix_dict:
                suffix_dict[sub].append(suf)
            else:
                suffix_dict[sub] = [suf]
        if exact:
            del suffix_dict['']
            for key in suffix_dict:
                suffix_dict[key] = helper([s[:pos] for s in suffix_dict[key]], None)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v[:pos])
        else:
            for key in suffix_dict:
                suffix_dict[key] = helper(suffix_dict[key], ml)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v)
    return helper(tuple(suffixes), None)
domain_remove = remove_suffix_preprocess(".com", ".net", ".edu", ".uk", '.tv', '.co.uk', '.org.uk')

cái cuối cùng có lẽ nhanh hơn đáng kể trong pypy sau đó là cpython. Biến thể regex có khả năng nhanh hơn phiên bản này đối với hầu hết các trường hợp không liên quan đến từ điển lớn của các hậu tố tiềm năng không thể được biểu diễn dễ dàng như một regex ít nhất là trong cPython.

Trong PyPy, biến thể regex gần như chắc chắn chậm hơn đối với số lượng lớn cuộc gọi hoặc chuỗi dài ngay cả khi mô-đun re sử dụng công cụ regex biên dịch DFA vì phần lớn chi phí của lambda sẽ được JIT tối ưu hóa.

Tuy nhiên, trong cPython, thực tế là mã c đang chạy của bạn cho regex gần như chắc chắn sẽ vượt qua các ưu điểm thuật toán của phiên bản bộ sưu tập hậu tố trong hầu hết các trường hợp.


2

Nếu bạn có nghĩa là chỉ tước phần mở rộng:

'.'.join('abcdc.com'.split('.')[:-1])
# 'abcdc'

Nó hoạt động với bất kỳ phần mở rộng nào, với các dấu chấm tiềm năng khác hiện có trong tên tệp. Nó chỉ đơn giản là tách chuỗi dưới dạng một danh sách trên các dấu chấm và nối nó mà không có phần tử cuối cùng.


2
import re

def rm_suffix(url = 'abcdc.com', suffix='\.com'):
    return(re.sub(suffix+'$', '', url))

Tôi muốn lặp lại câu trả lời này là cách diễn đạt nhất để làm điều đó. Tất nhiên, những điều sau đây sẽ tốn ít thời gian CPU hơn:

def rm_dotcom(url = 'abcdc.com'):
    return(url[:-4] if url.endswith('.com') else url)

Tuy nhiên, nếu CPU là cổ chai tại sao lại viết bằng Python?

Khi nào CPU là cổ chai? Trong trình điều khiển, có thể.

Ưu điểm của việc sử dụng biểu thức chính quy là khả năng sử dụng lại mã. Điều gì xảy ra nếu tiếp theo bạn muốn xóa '.me', chỉ có ba ký tự?

Cùng một mã sẽ thực hiện các mẹo:

>>> rm_sub('abcdc.me','.me')
'abcdc'

1

Trong trường hợp của tôi, tôi cần phải đưa ra một ngoại lệ vì vậy tôi đã làm:

class UnableToStripEnd(Exception):
    """A Exception type to indicate that the suffix cannot be removed from the text."""

    @staticmethod
    def get_exception(text, suffix):
        return UnableToStripEnd("Could not find suffix ({0}) on text: {1}."
                                .format(suffix, text))


def strip_end(text, suffix):
    """Removes the end of a string. Otherwise fails."""
    if not text.endswith(suffix):
        raise UnableToStripEnd.get_exception(text, suffix)
    return text[:len(text)-len(suffix)]


1

Giả sử bạn muốn xóa tên miền, bất kể đó là gì (.com, .net, v.v.). Tôi khuyên bạn nên tìm .và loại bỏ mọi thứ từ thời điểm đó.

url = 'abcdc.com'
dot_index = url.rfind('.')
url = url[:dot_index]

Ở đây tôi đang sử dụng rfindđể giải quyết vấn đề của các url abcdc.com.netnên được giảm tên abcdc.com.

Nếu bạn cũng quan tâm đến www.s, bạn nên kiểm tra chúng một cách rõ ràng:

if url.startswith("www."):
   url = url.replace("www.","", 1)

1 trong thay thế là dành cho edgecase lạ như www.net.www.com

Nếu url của bạn trở nên hoang dã hơn, hãy nhìn vào câu trả lời regex mà mọi người đã phản hồi.


1

Tôi đã sử dụng hàm rstrip tích hợp để thực hiện như sau:

string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test

Ý kiến ​​tồi. Hãy thử "test.ccom".
Shital Shah

Nhưng đây không phải là điểm của câu hỏi. Nó chỉ được yêu cầu loại bỏ một chuỗi con đã biết từ cuối chuỗi khác. Điều này hoạt động chính xác như mong đợi.
Alex

1

Bạn có thể sử dụng chia:

'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'

5
Khi a = 'www.computerbugs.com'kết quả này với 'www'
yairchu

0

Đây là một cách sử dụng hoàn hảo cho các biểu thức thông thường:

>>> import re
>>> re.match(r"(.*)\.com", "hello.com").group(1)
'hello'

5
Bạn cũng nên thêm $ để đảm bảo rằng bạn phù hợp với tên máy chủ kết thúc bằng ".com".
Cristian Ciupitu

0

Con trăn> = 3.9:

'abcdc.com'.removesuffix('.com')

Con trăn <3.9:

def remove_suffix(text, suffix):
    if text.endswith(suffix):
        text = text[:-len(suffix)]
    return text

remove_suffix('abcdc.com', '.com')

1
Câu trả lời của bạn cho Python 3.9 là một bản sao của câu trả lời này ở trên. Câu trả lời của bạn cho các phiên bản trước cũng đã được trả lời nhiều lần trong chuỗi này và sẽ không trả về bất cứ điều gì nếu chuỗi không có hậu tố.
Xavier Guihot
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.