Bagaimana cara menghapus substring dari ujung string dengan Python?


382

Saya memiliki kode berikut:

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

Saya mengharapkan: abcdc

Saya mendapatkan: abcd

Sekarang saya lakukan

url.rsplit('.com', 1)

Apakah ada cara yang lebih baik?


6
strip strip karakter yang diberikan dari kedua ujung string, dalam kasus Anda strip ".", "c", "o" dan "m".
truppo

6
Itu juga akan menghapus karakter-karakter itu dari depan string. Jika Anda hanya ingin menghapus dari akhir, penggunaan rstrip ()
Andre Miller

42
Ya. str.strip tidak melakukan apa yang Anda pikirkan. str.strip menghapus salah satu karakter yang ditentukan dari awal dan akhir string. Jadi, "acbacda" .strip ("ad") memberikan 'cbac'; a di awal dan da di akhir dilucuti. Bersulang.
scvalex

2
Plus, ini menghapus karakter dalam urutan apa pun : "site.ocm"> "site".
Eric O Lebigot

1
@scvalex, wow baru menyadari ini telah digunakan seperti itu selama berabad-abad - itu berbahaya karena kode sering terjadi untuk tetap bekerja
Flash

Jawaban:


556

striptidak berarti "hapus substring ini". x.strip(y)memperlakukan ysebagai satu set karakter dan menghapus setiap karakter dalam set itu dari ujung x.

Sebagai gantinya, Anda bisa menggunakan endswithdan mengiris:

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

Atau menggunakan ekspresi reguler :

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

4
Ya, saya sendiri berpikir bahwa contoh pertama, dengan tes endswith (), akan menjadi yang lebih baik; regex yang akan melibatkan beberapa penalti kinerja (parsing regex, dll.). Saya tidak akan menggunakan rsplit (), tapi itu karena saya tidak tahu persis apa yang ingin Anda capai. Saya pikir itu menghapus .com jika dan hanya jika itu muncul di akhir url? Solusi rsplit akan memberi Anda masalah jika Anda akan menggunakannya pada nama domain seperti 'www.commercialthingie.co.uk'
Steef

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

1
bagaimana jika saya menulis EXAMLPLE.COMnama domain tidak peka huruf besar-kecil. (Ini adalah suara untuk solusi regex)
Jasen

3
Ini bukan penulisan ulang, rsplit()solusinya tidak memiliki perilaku yang sama dengan yang endswith()ketika string asli tidak memiliki substring di akhir, tetapi di suatu tempat di tengah. Misalnya: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"tetapi"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef

1
Sintaks s[:-n]memiliki peringatan: untuk n = 0, ini tidak mengembalikan string dengan nol karakter terakhir dipotong, tetapi string kosong sebagai gantinya.
BlenderBender

90

Jika Anda yakin bahwa string hanya muncul di bagian akhir, maka cara paling sederhana adalah menggunakan 'ganti':

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

56
itu juga akan menggantikan seperti url www.computerhope.com. lakukan cek dengan endswith()dan harus baik-baik saja.
ghostdog74

72
"www.computerhope.com".endswith(".com")itu benar, masih akan pecah!

1
"Jika Anda yakin bahwa string hanya muncul di akhir," maksud Anda "Jika Anda yakin bahwa substring hanya muncul sekali"? ganti tampaknya berfungsi juga ketika substring ada di tengah, tetapi seperti komentar lain menyarankan itu akan menggantikan setiap kejadian substring, mengapa harus pada akhirnya saya tidak mengerti
idclev 463035818

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

4
Jika Anda tahu bahwa suffix tidak kosong (seperti ketika konstanta) maka: return text [: - len (suffix)]
MarcH

4
Terima kasih. Baris terakhir bisa disingkat:return text[:-len(suffix)]
Jabba

3
@ Jabba: Sayangnya, itu tidak akan bekerja untuk sufiks kosong, seperti yang disebutkan fuenfundachtzig.
yairchu

46

Karena sepertinya belum ada yang menunjukkan hal ini:

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

Ini harus lebih efisien daripada metode yang digunakan split()karena tidak ada objek daftar baru dibuat, dan solusi ini berfungsi untuk string dengan beberapa titik.


Wow itu trik yang bagus. Saya tidak bisa membuat ini gagal, tetapi saya juga kesulitan memikirkan cara-cara ini mungkin gagal. Saya suka tapi ini sangat "ajaib", sulit untuk mengetahui apa yang dilakukan dengan hanya melihatnya. Saya harus memproses setiap bagian dari garis mental untuk "mendapatkannya".
DevPlayer

14
Ini gagal jika string yang dicari TIDAK ada, dan itu salah menghapus karakter terakhir sebagai gantinya.
robbat2

25

Bergantung pada apa yang Anda ketahui tentang url Anda dan apa yang Anda coba lakukan. Jika Anda tahu bahwa itu akan selalu berakhir dengan '.com' (atau '.net' atau '.org'), maka

 url=url[:-4]

adalah solusi tercepat. Jika itu URL yang lebih umum maka Anda mungkin lebih baik melihat ke perpustakaan urlparse yang dilengkapi dengan python.

Jika Anda di sisi lain, Anda hanya ingin menghapus semuanya setelah final '.' dalam sebuah string kemudian

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

akan bekerja. Atau jika Anda ingin hanya menginginkan semuanya hingga yang pertama '.' lalu coba

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

16

Jika Anda tahu itu ekstensi, maka

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

Ini bekerja sama baiknya dengan abcdc.comatau www.abcdc.comatau abcdc.[anything]dan lebih bisa diperluas.


12

Dalam satu baris:

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

8

Bagaimana dengan url[:-4]?


Tampaknya hampir pasti mengarah ke bug setelah Anda terkena .caatau .co.ukurl.
Peter

7

Untuk url (karena tampaknya menjadi bagian dari topik dengan contoh yang diberikan), orang dapat melakukan sesuatu seperti ini:

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)

Keduanya akan menampilkan: ('http://www.stackoverflow', '.com')

Ini juga dapat digabungkan dengan str.endswith(suffix)jika Anda hanya perlu membagi ".com", atau apa pun yang spesifik.


5

url.rsplit ('. com', 1)

tidak benar.

Apa yang sebenarnya perlu Anda tulis adalah

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

, dan itu terlihat IMHO cukup ringkas.

Namun, preferensi pribadi saya adalah opsi ini karena hanya menggunakan satu parameter:

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

1
Partisi +1 lebih disukai ketika hanya satu split yang diperlukan karena selalu mengembalikan jawaban, IndexError tidak akan terjadi.
Gringo Suave


2

Jika Anda perlu menghapus beberapa ujung string jika ada, lakukan apa-apa. Solusi terbaik saya Anda mungkin ingin menggunakan salah satu dari 2 implementasi pertama namun saya telah memasukkan 3 untuk kelengkapan.

Untuk akhiran konstan:

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'

Untuk 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"

Untuk koleksi sufiks konstan, cara tercepat tanpa asimptot untuk sejumlah besar panggilan:

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')

yang terakhir mungkin secara signifikan lebih cepat di pypy kemudian cpython. Varian regex kemungkinan lebih cepat dari ini untuk hampir semua kasus yang tidak melibatkan kamus besar sufiks potensial yang tidak dapat dengan mudah direpresentasikan sebagai regex setidaknya dalam cPython.

Dalam PyPy varian regex hampir pasti lebih lambat untuk sejumlah besar panggilan atau string panjang bahkan jika modul ulang menggunakan mesin kompilasi regex DFA karena sebagian besar overhead dari lambda akan dioptimalkan oleh JIT.

Namun dalam cPython fakta bahwa Anda menjalankan kode c untuk regex membandingkan hampir pasti cara keuntungan algoritmik dari versi koleksi suffix di hampir semua kasus.


2

Jika Anda bermaksud hanya menghapus ekstensi:

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

Ia bekerja dengan ekstensi apa pun, dengan titik-titik potensial lainnya yang ada dalam nama file juga. Ini hanya membagi string sebagai daftar pada titik-titik dan bergabung tanpa elemen terakhir.


2
import re

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

Saya ingin mengulangi jawaban ini sebagai cara paling ekspresif untuk melakukannya. Tentu saja, yang berikut ini akan memakan waktu lebih singkat:

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

Namun, jika CPU adalah leher botol mengapa menulis dengan Python?

Kapan CPU menjadi leher botol? Di driver, mungkin.

Keuntungan menggunakan ekspresi reguler adalah penggunaan kembali kode. Bagaimana jika Anda selanjutnya ingin menghapus '.me', yang hanya memiliki tiga karakter?

Kode yang sama akan melakukan trik:

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

1

Dalam kasus saya, saya perlu mengajukan pengecualian sehingga saya melakukannya:

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

Dengan asumsi Anda ingin menghapus domain, apa pun itu (.com, .net, dll). Saya sarankan untuk menemukan .dan menghapus semuanya sejak saat itu.

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

Di sini saya menggunakan rfinduntuk memecahkan masalah url seperti abcdc.com.netyang harus direduksi menjadi namanya abcdc.com.

Jika Anda juga khawatir tentang www.s, Anda harus secara eksplisit memeriksanya:

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

1 di ganti adalah untuk edgecases aneh seperti www.net.www.com

Jika url Anda menjadi lebih liar dari itu, lihat pada regex jawaban yang telah ditanggapi orang.


1

Saya menggunakan fungsi rstrip bawaan untuk melakukannya seperti ikuti:

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

Ide buruk. Coba "test.ccom".
Shital Shah

Tapi ini bukan inti dari pertanyaan itu. Itu hanya diminta untuk menghapus substring yang diketahui dari ujung yang lain. Ini bekerja persis seperti yang diharapkan.
Alex

1

Anda dapat menggunakan split:

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

5
Saat a = 'www.computerbugs.com'ini hasil dengan 'www'
yairchu

0

Ini adalah penggunaan yang sempurna untuk ekspresi reguler:

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

5
Anda juga harus menambahkan $ untuk memastikan bahwa Anda mencocokkan nama host yang diakhiri dengan ".com".
Cristian Ciupitu

0

Python> = 3.9:

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

Python <3.9:

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

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

1
Jawaban Anda untuk Python 3.9 adalah duplikat dari jawaban di atas. Jawaban Anda untuk versi sebelumnya juga telah berkali-kali dijawab di utas ini dan tidak akan mengembalikan apa pun jika string tidak memiliki akhiran.
Xavier Guihot
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.