Як видалити підрядку з кінця рядка в 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.