Как удалить подстроку из конца строки в Python?


383

У меня есть следующий код:

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

Я ожидал: abcdc

Я получил: abcd

Сейчас делаю

url.rsplit('.com', 1)

Есть ли способ лучше?


6
strip удаляет символы, заданные с обоих концов строки, в вашем случае она удаляет ".", "c", "o" и "m".
Truppo

6
Он также удалит эти символы с начала строки. Если вы просто хотите, чтобы его удалили с конца, используйте rstrip ()
Andre Miller

42
Да. str.strip не делает то, что вы думаете. str.strip удаляет любой из символов, указанных в начале и конце строки. Итак, «acbacda» .strip («ad») дает «cbac»; А в начале и да в конце были раздеты. Приветствия.
Scvalex

2
Плюс, это удаляет символы в любом порядке : "site.ocm"> "site".
Эрик О Лебиго

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

Ответы:


557

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
Да, я сам думаю, что первый пример с тестом endwith () был бы лучшим; регулярное выражение может повлечь за собой некоторое снижение производительности (разбор регулярного выражения и т. д.). Я бы не стал использовать rsplit (), но это потому, что я не знаю, чего именно вы пытаетесь достичь. Я полагаю, что он удаляет .com, если и только если он появляется в конце URL? Решение rsplit доставит вам неприятности, если вы будете использовать его на доменных именах, таких как «www.commercialthingie.co.uk»
Steef

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

1
Что делать, если я пишу EXAMLPLE.COMдоменные имена не чувствительны к регистру. (Это голосование за решение регулярных выражений)
Jasen

3
Это не перезапись, rsplit()решение не имеет такого же поведения, как и в endswith()случае, когда исходная строка не имеет подстроки в конце, но где-то посередине. Например: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"но"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef

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)]
Джабба

3
@Jabba: К сожалению, это не сработает для пустых суффиксов, как упомянул fuenfundachtzig.
Яирчу

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]

И выглядит ИМХО довольно лаконично

Тем не менее, я предпочитаю эту опцию, потому что она использует только один параметр:

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 вариант регулярного выражения почти наверняка медленнее для большого количества вызовов или длинных строк, даже если модуль re использует механизм регулярных выражений DFA для компиляции, поскольку JIT оптимизирует подавляющее большинство служебных данных лямбды.

В cPython, однако, тот факт, что ваш выполняющийся код c для регулярных выражений почти наверняка сравнивает алгоритмические преимущества версии коллекции суффиксов почти во всех случаях.



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)

Однако, если процессор является узким местом, зачем писать на Python?

Во всяком случае, когда CPU - это горлышко бутылки? В драйверах, может быть.

Преимущество использования регулярных выражений заключается в возможности повторного использования кода. Что если в следующий раз вы захотите удалить «.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".
Шиталь Шах

Но это не главное. Просто попросили удалить известную подстроку с конца другой. Это работает точно так, как ожидалось.
Алекс

0

Это идеальное использование для регулярных выражений:

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

5
Вы также должны добавить $, чтобы убедиться, что вы соответствуете именам хостов, оканчивающимся на «.com».
Кристиан Чиупиту

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

2
Ваш ответ для Python 3.9 является дубликатом этого ответа выше. На ваш ответ за предыдущие версии также много раз отвечали в этой теме, и он ничего не даст, если строка не имеет суффикса.
Ксавье Гихот
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.