Як видалити підрядку з кінця рядка в Python?


382

У мене є такий код:

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

Я очікував: abcdc

Я зрозумів, я отримав: abcd

Тепер я

url.rsplit('.com', 1)

Чи є кращий спосіб?


6
смужка накреслює символи, надані з обох кінців рядка, у вашому випадку це смужки ".", "c", "o" та "m".
truppo

6
Це також видалить ці символи з передньої частини рядка. Якщо ви просто хочете, щоб його зняли з кінця, використовуйте rstrip ()
Андре Міллер

42
Так. str.strip не робить те, що, на вашу думку, робить. str.strip видаляє будь-який із символів, зазначених на початку та в кінці рядка. Отже, "acbacda" .strip ("реклама") дає "cbac"; a на початку та da в кінці були позбавлені. Ура.
scvalex

2
Крім того, це видаляє символи в будь-якому порядку : "site.ocm"> "сайт".
Ерік О Лебігот

1
@scvalex, ух, щойно зрозумів це, використовуючи його таким чином протягом століть - це небезпечно, оскільки код часто так чи інакше працює
Flash

Відповіді:


556

stripне означає "видалити цю підрядку". x.strip(y)трактує yяк набір символів і знімає будь-які символи в цьому наборі з кінцівx .

Натомість ви можете використовувати endswithта нарізати:

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

Або використовуючи регулярні вирази :

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

4
Так, я сам думаю, що перший приклад із тестом endsith () був би кращим; регулярний вираз передбачає певну ефективність покарання (розбір регексу тощо). Я б не ходив з rsplit (), але це тому, що я не знаю, чого ви саме намагаєтесь досягти. Я вважаю, що це видалення .com, якщо і лише якщо він з’являється в кінці URL-адреси? Рішення rsplit створить вам проблеми, якщо ви будете використовувати його в доменних іменах, таких як "
www.com commercialthingie.co.uk

13
url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
Бурхан Халід

1
що робити, якщо я пишу EXAMLPLE.COMдоменні імена, не відрізняються від регістру. (Це голосування за рішення регулярного виразу)
Ясен

3
Це не перезапис, rsplit()рішення не має такої поведінки, як у endswith()тих, коли в оригінальній рядку немає підрядка в кінці, але десь посередині. Наприклад: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"але"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Стіф

1
У синтаксисі s[:-n]є застереження: адже n = 0, це не повертає рядок з відсіченими останніми нульовими символами, а замість цього порожній рядок.
BlenderBender

90

Якщо ви впевнені, що рядок відображається лише в кінці, найпростішим способом було б скористатись "Замінити":

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

56
це також замінить URL-адресу, як www.computerhope.com. зробіть перевірку endswith()і має бути добре.
ghostdog74

72
"www.computerhope.com".endswith(".com")це правда, вона все одно зламається!

1
"Якщо ви впевнені, що рядок відображається лише в кінці", ви маєте на увазі "Якщо ви впевнені, що підрядка з'являється лише один раз"? замість, здається, працює і тоді, коли підрядок знаходиться в середині, але, як свідчить інший коментар, він замінить будь-яку появу підрядки, чому це має бути в кінці, я не розумію
idclev 463035818

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

4
Якщо ви знаєте, що суфікс не порожній (наприклад, коли це константа), тоді: поверніть текст [: - len (суфікс)]
MarcH

4
Дякую. Останній рядок можна було скоротити:return text[:-len(suffix)]
Jabba

3
@Jabba: На жаль, це не працює для порожніх суфіксів, як згадував fuenfundachtzig.
yairchu

46

Оскільки, здається, ще ніхто цього не вказав:

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

Це повинно бути більш ефективним, ніж методи, що використовують split()новий об'єкт списку, і це рішення працює для рядків з кількома крапками.


Нічого собі, це приємна хитрість. Я не міг зробити це невдалим, але мені теж важко було придумати способи, як це може вийти з ладу. Мені це подобається, але це дуже "магічно", важко зрозуміти, що це робить, просто подивившись на це. Мені довелося подумки обробити кожну частину рядка, щоб "дістати її".
DevPlayer

14
Це не вдається, якщо шуканий рядок НЕ присутній, і він неправильно видаляє останній символ замість цього.
robbat2

25

Залежить від того, що ви знаєте про свою URL-адресу і що саме ви намагаєтеся робити. Якщо ви знаєте, що він завжди закінчуватиметься в '.com' (або '.net' або '.org')

 url=url[:-4]

- найшвидше рішення. Якщо це більш загальні URL-адреси, то вам, мабуть, краще заглянути в бібліотеку urlparse, яка постачається з python.

Якщо ви, з іншого боку, просто хочете видалити все після фіналу ". то в рядку

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

буду працювати. Або якщо ви просто хочете, щоб все було до першого ". то спробуйте

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

16

Якщо ви знаєте, що це розширення, значить

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

Це однаково добре працює з abcdc.comабо www.abcdc.comабо abcdc.[anything]і є більш розширеним.




7

Для URL-адрес (як це здається частиною теми на наведеному прикладі) можна зробити щось подібне:

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)

Обидва будуть виводити: ('http://www.stackoverflow', '.com')

Це також можна поєднувати, str.endswith(suffix)якщо вам потрібно просто розділити ".com" або що-небудь конкретне.


5

url.rsplit ('. com', 1)

не зовсім правильно.

Те, що вам насправді потрібно було б написати, - це

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

, і це виглядає досить лаконічно IMHO.

Однак мої особисті переваги - це цей варіант, оскільки він використовує лише один параметр:

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

1
Розділ +1 є кращим, коли потрібен лише один розділ, оскільки він завжди повертає відповідь, IndexError не відбудеться.
Gringo Suave


2

Якщо вам потрібно зняти якийсь кінець рядка, якщо він існує, інакше нічого не робіть. Мої найкращі рішення. Ймовірно, ви захочете використовувати одну з перших двох реалізацій, однак я включив третю для повноти.

Для постійного суфіксу:

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'

Для регулярного вираження:

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"

Для колекції постійних суфіксів асимптотично найшвидший спосіб для великої кількості дзвінків:

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

остаточний, ймовірно, значно швидший у pypy, ніж у cpython. Варіант регулярного виразів швидше, ніж це практично для всіх випадків, що не включають величезні словники потенційних суфіксів, які не можуть бути легко представлені як регулярні вирази принаймні в cPython.

У PyPy варіант регулярного виведення майже напевно повільніше для великої кількості дзвінків або довгих рядків, навіть якщо модуль повторного використання використовує DFA-компілюючий регекс-движок, оскільки переважна більшість накладних витрат лямбда буде оптимізована JIT.

У cPython, однак, той факт, що ваш запущений код коду для регулярних виразів, майже напевно порівнює способи алгоритмічних переваг версії суффіксного збірника майже у всіх випадках.


2

Якщо ви хочете зняти лише розширення:

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

Він працює з будь-яким розширенням, а також можливі інші точки, що існують у імені файлу. Він просто розбиває рядок як список на точки і приєднується до нього без останнього елемента.


2
import re

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

Я хочу повторити цю відповідь як найвиразніший спосіб це зробити. Зрозуміло, для процесора потрібно менше часу:

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

Однак якщо CPU - це горлечко для пляшок, чому б писати в Python?

Коли процесор все-таки є шийкою пляшки? У водіїв, можливо.

Перевагами використання регулярного вираження є повторне використання коду. Що робити, якщо ви бажаєте видалити ".me", який містить лише три символи?

Цей же код зробив би трюк:

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

1

У моєму випадку мені потрібно було зробити виняток, тому я зробив:

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

Припустимо, що ви хочете видалити домен, незалежно від того, що він є (.com, .net тощо). Я рекомендую знайти .і видалити все з цього моменту.

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

Тут я використовую rfindдля вирішення проблеми URL-адрес, abcdc.com.netякі слід звести до назви abcdc.com.

Якщо ви також стурбовані www.s, вам слід чітко перевірити їх:

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

1 заміни призначений для дивних крайових випадків www.net.www.com

Якщо ваша URL-адреса стає дивішою, ніж це дивіться на відповіді з питань регулярного вираження, на які люди відповіли.


1

Я використовував вбудовану функцію rstrip, щоб зробити це як слід:

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

Погана ідея. Спробуйте "test.ccom".
Shital Shah

Але це не сенс питання. Просто було запропоновано видалити відому підрядку з кінця іншої. Це працює точно так, як очікувалося.
Олексій

1

Ви можете використовувати спліт:

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

5
Коли a = 'www.computerbugs.com'це призводить до 'www'
yairchu

0

Це ідеальне використання для регулярних виразів:

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

5
Ви також повинні додати $, щоб переконатися, що ви узгоджуєте імена хостів, що закінчуються на ".com".
Крістіан Цюпіту

0

Python> = 3,9:

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

Пітон <3,9:

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

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

1
Ваша відповідь на Python 3.9 - це дублікат цієї відповіді вище. На вашу відповідь за попередні версії також багато разів відповідали в цій темі, і нічого не поверне, якщо рядок не має суфікса.
Xavier Guihot
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.