Удалить определенные символы из строки в Python

548

Я пытаюсь удалить определенные символы из строки, используя Python. Это код, который я использую прямо сейчас. К сожалению, похоже, что ничего не делает со строкой.

for char in line:
    if char in " ?.!/;:":
        line.replace(char,'')

Как мне сделать это правильно?

Мэтт Филлипс
источник
23
Прошло более 5 лет, но как об использовании filterфункции и лямбда - выражения: filter(lambda ch: ch not in " ?.!/;:", line). Я думаю, довольно сжато и эффективно. Конечно, он возвращает новую строку, которой вы должны будете присвоить имя.
Джон Ред
3
@JohnRed: На самом деле он возвращает итератор, который возвращает список символов, но если вы добавите это в ответ, некоторые из нас будут рады проголосовать за него.
Билл Белл
@BillBell: PS: это итератор в Python3 и строка, кортеж или список в Python2
serv-inc

Ответы:

628

Строки в Python неизменны (не могут быть изменены). Из-за этого эффект line.replace(...)состоит в том, чтобы просто создать новую строку, а не изменить старую. Вам нужно перепривязать (назначить) его line, чтобы эта переменная приняла новое значение с удалением этих символов.

Кроме того, то, как вы это делаете, будет относительно медленным. Это также, вероятно, будет немного смущать опытных питонаторов, которые увидят дважды вложенную структуру и на мгновение подумают, что происходит нечто более сложное.

Начиная с Python 2.6 и более новых версий Python 2.x *, вы можете использовать вместо этого str.translate(но читайте дальше о различиях в Python 3):

line = line.translate(None, '!@#$')

или замена регулярного выражения на re.sub

import re
line = re.sub('[!@#$]', '', line)

Символы, заключенные в квадратные скобки, составляют класс символов . Любые символы в lineэтом классе заменяются вторым параметром sub: пустой строкой.

В Python 3 строки являются Unicode. Вам придется переводить немного по-другому. kevpie упоминает об этом в комментарии к одному из ответов, и это отмечено в документации дляstr.translate .

При вызове translateметода строки Unicode вы не можете передать второй параметр, который мы использовали выше. Вы также не можете передать Noneв качестве первого параметра. Вместо этого вы передаете таблицу перевода (обычно словарь) как единственный параметр. Эта таблица отображает порядковые значения символов (т. Е. Результат обращения ordк ним) с порядковыми значениями символов, которые должны их заменить, или - для нас - Noneчтобы указать, что они должны быть удалены.

Таким образом, чтобы сделать вышеупомянутый танец со строкой Unicode, вы бы назвали что-то вроде

translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)

Здесь dict.fromkeysи mapиспользуются для краткой генерации словаря, содержащего

{ord('!'): None, ord('@'): None, ...}

Еще проще, как говорит другой ответ , создать таблицу перевода на месте:

unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})

Или создайте ту же таблицу перевода с str.maketrans:

unicode_line = unicode_line.translate(str.maketrans('', '', '!@#$'))

* для совместимости с более ранними Pythons, вы можете создать «нулевую» таблицу перевода для передачи вместо None:

import string
line = line.translate(string.maketrans('', ''), '!@#$')

Здесь string.maketransиспользуется для создания таблицы перевода , которая представляет собой просто строку, содержащую символы с порядковыми значениями от 0 до 255.

созерцаемое
источник
26
В Python3 line.translateпринимает только один аргумент, и первое решение не будет работать
marczoid
33
В python3 str.translate () не принимает второй аргумент. Итак, ваш ответ станет line.translate({ord(i):None for i in '!@#$'})
Навин
1
Как и любой другой персонаж. Python позволяет использовать пары одинарных или двойных кавычек. Так что вы просто пишите "'"для набора символов.
интуитивно
2
Комментарий @ naveen выше работал для меня. Пифония 2.7.13. В моем случае я хотел раздеть "и" персонажей:notes = notes.translate({ord(i):None for i in '\"\''})
RyanG
1
В Python 3 вы можете использовать unicode_line.translate(str.maketrans('', '', '!@#$')). Илиunicode_line.translate(dict.fromkeys(map(ord, '!@#$')))
Мартин Питерс
234

Я здесь упускаю суть, или это просто следующее:

string = "ab1cd1ef"
string = string.replace("1","") 

print string
# result: "abcdef"

Поместите это в цикл:

a = "a!b@c#d$"
b = "!@#$"
for char in b:
    a = a.replace(char,"")

print a
# result: "abcd"
gsbabil
источник
26
Это сделает копию строки в каждом цикле, что может быть нежелательно. Также это не очень хороший Python. В Python вы бы вместо этого for char in b: a=a.replace(char,"")
зациклились
2
использование пользовательских переменных, которые перекрывают системные классы, не очень хорошая идея. Вам лучше использовать переменную STRING вместо STR и C вместо CHAR.
Айрат
Должен быть string=string.replace("1","")вместо этого. Вы как-то сказали это в циклической части вашего примера, но большинство людей не будут вдаваться в подробности вашего ответа до тех пор, пока они не возьмутся за код, чтобы немного разобраться с таким простым вопросом.
CodeMed
Хорошее решение, но не такое Python-esk, как другие.
Стив
45
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'
ghostdog74
источник
используйте другой разделитель строк, такой как '' 'или "
ALisboa
1
Если у вас много запрещенных символов, вы можете ускорить код, превратив его в набор. blacklist = set('?:!/;')а потом''.join(c for c in line if c not in blacklist)
Борис
32

Легко peasy с re.subрегулярным выражением от Python 3.5

re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)

пример

>>> import re

>>> line = 'Q: Do I write ;/.??? No!!!'

>>> re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
'QDoIwriteNo'

объяснение

В регулярных выражениях (регулярное выражение) |представляет собой логическое ИЛИ и \экранирует пробелы и специальные символы, которые могут быть действительными командами регулярного выражения. Принимая во внимание, что subозначает замену, в этом случае с пустой строкой ''.

Серж Строобандт
источник
22

Для обратного требования разрешать только определенные символы в строке вы можете использовать регулярные выражения с оператором дополнения набора [^ABCabc]. Например, чтобы удалить все, кроме букв ascii, цифр и дефиса:

>>> import string
>>> import re
>>>
>>> phrase = '  There were "nine" (9) chick-peas in my pocket!!!      '
>>> allow = string.letters + string.digits + '-'
>>> re.sub('[^%s]' % allow, '', phrase)

'Therewerenine9chick-peasinmypocket'

Из документации по регулярным выражениям python :

Символы, которые не находятся в пределах диапазона, могут быть сопоставлены путем дополнения набора. Если первый символ набора - '^'все символы, которые не входят в набор, будут сопоставлены. Например, [^5]будет соответствовать любой символ, кроме «5», и [^^]будет соответствовать любой символ, кроме '^'. ^не имеет особого значения, если это не первый символ в наборе.

cod3monk3y
источник
19

У Аскера почти было это. Как и большинство вещей в Python, ответ проще, чем вы думаете.

>>> line = "H E?.LL!/;O:: "  
>>> for char in ' ?.!/;:':  
...  line = line.replace(char,'')  
...
>>> print line
HELLO

Вам не нужно выполнять вложенный цикл if / for, но вам НЕОБХОДИМО проверять каждый символ отдельно.

mgold
источник
да, я знаю, возможно, слишком поздно, но должно сработать, если вы избежите этого. Например: line = line.replace ('`', '') читайте дальше: learnpythonthehardway.org/book/ex10.html
Aiyion.Prime
Это, вероятно,
неэффективно,
14
line = line.translate(None, " ?.!/;:")
Мухаммед Алкарури
источник
2
+1 При использовании юникода требуется настроить перевод для удаления вместо строки удаления. docs.python.org/library/stdtypes.html#str.translate
kevpie
Это отличное предложение (ref: docs.python.org/2/library/string.html#string.translate ) Замечание по юникоду также хорошо.
cgseller
11
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'
eatkin
источник
2
Мой ответ действительно дает решение первоначального вопроса, но я также был заинтересован (возможно, также ОП) в обратной связи о том, почему мое решение может быть не идеальным. Должен ли я создать новый вопрос и сослаться на этот для контекста?
eatkin
Это получает мой голос. Питон лаконичен
Стив
9

Строки неизменны в Python. replaceМетод возвращает новую строку после замены. Пытаться:

for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')
Грег Хьюгилл
источник
Как вы можете перебрать строку и изменить ее одновременно?
Eumiro
1
@eumiro: итерация продолжается над оригиналом line .
Грег Хьюгилл
хорошо знать! Поэтому, если я перебираю массив, я перебираю исходный массив. Итерация по итератору была бы невозможна.
Eumiro
9

Я был удивлен, что никто еще не рекомендовал использовать встроенную функцию фильтра .

    import operator
    import string # only for the example you could use a custom string

    s = "1212edjaq"

Скажем, мы хотим отфильтровать все, что не является числом. Использование встроенного метода фильтра «... эквивалентно выражению генератора (элемент для элемента в итерируемой функции (элемент))» [ Python 3 Builtins: Filter ]

    sList = list(s)
    intsList = list(string.digits)
    obj = filter(lambda x: operator.contains(intsList, x), sList)))

В Python 3 это возвращает

    >>  <filter object @ hex>

Чтобы получить печатную строку,

    nums = "".join(list(obj))
    print(nums)
    >> "1212"

Я не уверен, как фильтр ранжируется с точки зрения эффективности, но хорошо знать, как его использовать при выполнении списочных вычислений и тому подобное.

ОБНОВИТЬ

Логично, что поскольку фильтр работает, вы также можете использовать понимание списков, и из того, что я прочитал, он должен быть более эффективным, потому что лямбды являются менеджерами хедж-фондов Уолл-стрит в мире функций программирования. Еще одним плюсом является то, что это однострочник, который не требует импорта. Например, используя ту же строку 's', определенную выше,

      num = "".join([i for i in s if i.isdigit()])

Вот и все. Возвращаемым будет строка всех символов, которые являются цифрами в исходной строке.

Если у вас есть определенный список допустимых / неприемлемых символов, вам нужно только отрегулировать часть «если» в понимании списка.

      target_chars = "".join([i for i in s if i in some_list]) 

или, в качестве альтернативы,

      target_chars = "".join([i for i in s if i not in some_list])
Дан Темкин
источник
Нет причин использовать, operator.containsесли вы используете в lambdaлюбом случае. lambda x: operator.contains(intsList, x)должно быть написано lambda x: x in intsList, или если вы пытаетесь получить проверку уровня C, intsList.__contains__(нет lambdaвообще) добьется цели.
ShadowRanger
8

Используя filter, вам просто понадобится одна строка

line = filter(lambda char: char not in " ?.!/;:", line)

Это обрабатывает строку как итеративную и проверяет каждый символ, если lambdaвозвращается True:

>>> help(filter)
Help on built-in function filter in module __builtin__:

filter(...)
    filter(function or None, sequence) -> list, tuple, or string

    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a tuple
    or string, return the same type, else return a list.
Serv-вкл
источник
4

Вот несколько возможных способов решения этой задачи:

def attempt1(string):
    return "".join([v for v in string if v not in ("a", "e", "i", "o", "u")])


def attempt2(string):
    for v in ("a", "e", "i", "o", "u"):
        string = string.replace(v, "")
    return string


def attempt3(string):
    import re
    for v in ("a", "e", "i", "o", "u"):
        string = re.sub(v, "", string)
    return string


def attempt4(string):
    return string.replace("a", "").replace("e", "").replace("i", "").replace("o", "").replace("u", "")


for attempt in [attempt1, attempt2, attempt3, attempt4]:
    print(attempt("murcielago"))

PS: вместо использования "?.! / ;:" в примерах используются гласные ... и да, "murcielago" - это испанское слово "летучая мышь" ... смешное слово, поскольку оно содержит все гласные :)

PS2: Если вы заинтересованы в производительности, вы можете измерить эти попытки с помощью простого кода вроде:

import timeit


K = 1000000
for i in range(1,5):
    t = timeit.Timer(
        f"attempt{i}('murcielago')",
        setup=f"from __main__ import attempt{i}"
    ).repeat(1, K)
    print(f"attempt{i}",min(t))

В моей коробке вы получите:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465

Так что, похоже, попытка 4 является самой быстрой для этого конкретного ввода.

BPL
источник
1
Вы создаете бесполезный listв attempt1и кортеж может быть переписан "aeiou"для простоты пользы (удаление [и ]превратитесь в в генератор без создания списка). Вы создаете тонны одноразовых промежуточных строк attemt2, вы используете несколько приложений регулярных выражений, в attempt3которых вы можете использовать их r'[aeiou]'за один проход. у каждого есть свои недостатки - приятно видеть разные способы сделать что-то, но, пожалуйста, исправьте их, чтобы они тоже были хорошими попытками
Патрик Артнер,
1
@PatrickArtner Вы абсолютно правы ... из десятков способов, которые я намеревался выполнить для этой задачи, я выбрал более медленные (хотел показать ОП несколько простых) ... Тем не менее, после того, как вы ребята закрыли другую ветку Я потерял мотивацию приложить больше усилий на эту уже отвеченную старую ветку, так что ... :). Спасибо за очки, хотя.
BPL
@PatrickArtner Ладно ... просто ради того, чтобы добавить новый, "попытки4" ... не измерил, но я думаю, что нужно быть быстрее
BPL
1
@PatrickArtner Отредактировано ... try4 было самым быстрым из небольшого набора попыток. Во всяком случае, я не трачу больше времени на эти вещи :)
BPL
3

Вот моя Python 2/3 совместимая версия. С тех пор как переводчик API изменился.

def remove(str_, chars):
    """Removes each char in `chars` from `str_`.

    Args:
        str_: String to remove characters from
        chars: String of to-be removed characters

    Returns:
        A copy of str_ with `chars` removed

    Example:
            remove("What?!?: darn;", " ?.!:;") => 'Whatdarn'
    """
    try:
        # Python2.x
        return str_.translate(None, chars)
    except TypeError:
        # Python 3.x
        table = {ord(char): None for char in chars}
        return str_.translate(table)
Брайс Гуинта
источник
Я бы использовал dict.fromkeys(map(ord, '!@#$'))для создания карты.
Мартин Питерс
mapкак правило, менее читаемо, чем понимание списка / dict / set / generator. Настолько, что Гвидо хотел убрать это из языка . Использование fromkeysтакже немного умен и требует проверки документов.
Брайс Гуинта
1
@MartijnPieters: Для Python 3 так и должно быть str.maketrans('', '', chars), который обрабатывает ordпреобразование и dictконструкцию все за один раз (не говоря уже о том, чтобы быть более очевидным в намерениях, так как он спарен с str.translate).
ShadowRanger
1
#!/usr/bin/python
import re

strs = "how^ much for{} the maple syrup? $20.99? That's[] ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!|a|b]',r' ',strs)#i have taken special character to remove but any #character can be added here
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)#for removing special character
print nestr
пкм
источник
Вы имеете в виду речевые отметки? re имеет обратную косую черту, чтобы экранировать код и рассматривать 'как строку. docs.python.org/2/library/re.html
JasTonAChair
1

Как насчет этого:

def text_cleanup(text):
    new = ""
    for i in text:
        if i not in " ?.!/;:":
            new += i
    return new
Wariat
источник
1
Не могли бы вы более подробно проработать свой ответ, добавив немного больше описания предлагаемого вами решения?
abarisone
Добавление в список, а затем использование объединения будет более эффективным, чем конкатенация
OneCricketeer
1

Вы также можете использовать функцию для замены регулярного выражения другого типа или другого шаблона с использованием списка. При этом вы можете смешивать регулярное выражение, класс символов и действительно базовый текстовый шаблон. Это действительно полезно, когда вам нужно заменить много элементов, таких как HTML.

* Примечание: работает с Python 3.x

import re  # Regular expression library


def string_cleanup(x, notwanted):
    for item in notwanted:
        x = re.sub(item, '', x)
    return x

line = "<title>My example: <strong>A text %very% $clean!!</strong></title>"
print("Uncleaned: ", line)

# Get rid of html elements
html_elements = ["<title>", "</title>", "<strong>", "</strong>"]
line = string_cleanup(line, html_elements)
print("1st clean: ", line)

# Get rid of special characters
special_chars = ["[!@#$]", "%"]
line = string_cleanup(line, special_chars)
print("2nd clean: ", line)

В функции string_cleanup она принимает вашу строку x и ваш список нежелательных в качестве аргументов. Для каждого элемента в этом списке элементов или шаблона, если требуется замена, это будет сделано.

Выход:

Uncleaned:  <title>My example: <strong>A text %very% $clean!!</strong></title>
1st clean:  My example: A text %very% $clean!!
2nd clean:  My example: A text very clean
Djidiouf
источник
1

Мой метод, который я бы использовал, вероятно, не будет работать так же эффективно, но он очень прост. Я могу удалить несколько символов в разных позициях одновременно, используя нарезку и форматирование. Вот пример:

words = "things"
removed = "%s%s" % (words[:3], words[-1:])

Это приведет к тому, что слово «this» будет «удалено».

Форматирование может быть очень полезным для печати переменных в середине строки печати. Он может вставить любой тип данных, используя %, за которым следует тип данных переменной; все типы данных могут использовать % s , а числа с плавающей запятой (или десятичные числа) и целые числа могут использовать % d .

Нарезка может быть использована для сложного контроля над строками. Когда я помещаю слова [: 3] , это позволяет мне выбрать все символы в строке с начала (двоеточие перед числом, это будет означать «от начала до») до 4-го символа (включая 4-й персонаж). Причина, по которой 3 равняется до 4-й позиции, заключается в том, что Python начинается с 0. Затем, когда я помещаю слово [-1:] , это означает 2-й последний символ в конце (двоеточие находится за числом). Установка -1 приведет к подсчету Python от последнего символа, а не от первого. Снова Python начнется с 0. Итак, слово [-1:] основном означает «от второго последнего символа до конца строки.

Таким образом, обрезая символы перед персонажем, которого я хочу удалить, и символы после и помещая их вместе, я могу удалить нежелательного персонажа. Думайте об этом как о колбасе.В середине это грязно, поэтому я хочу избавиться от этого. Я просто отрезаю два конца, которые хочу, затем соединяю их без ненужной части посередине.

Если я хочу удалить несколько последовательных символов, я просто сдвигаю числа в [] (часть среза). Или, если я хочу удалить несколько символов из разных позиций, я могу просто объединить несколько слайсов одновременно.

Примеры:

 words = "control"
 removed = "%s%s" % (words[:2], words[-2:])

удалено равно "круто".

words = "impacts"
removed = "%s%s%s" % (words[1], words[3:5], words[-1])

удален равно 'macs'.

В этом случае [3: 5] означает символ в позиции 3 через символ в позиции 5 (исключая символ в конечной позиции).

Помните, что Python начинает считать с 0 , так что вам тоже нужно будет.

oisinvg
источник
0

Попробуй это:

def rm_char(original_str, need2rm):
    ''' Remove charecters in "need2rm" from "original_str" '''
    return original_str.translate(str.maketrans('','',need2rm))

Этот метод хорошо работает в Python 3.5.2

Джозеф ли
источник
0

Вы можете использовать замену регулярного выражения re модуля. Использование выражения ^ позволяет вам выбрать именно то, что вы хотите от вашей строки.

    import re
    text = "This is absurd!"
    text = re.sub("[^a-zA-Z]","",text) # Keeps only Alphabets
    print(text)

Выходом к этому будет «Thisisabsurd». Появятся только те вещи, которые указаны после символа ^.

Шреас раджеш
источник
0

Строковый метод replaceне изменяет исходную строку. Он оставляет оригинал один и возвращает измененную копию.

То, что вы хотите, это что-то вроде: line = line.replace(char,'')

def replace_all(line, )for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')
    return line

Однако создание новой строки каждый раз, когда удаляется символ, очень неэффективно. Вместо этого я рекомендую следующее:

def replace_all(line, baddies, *):
    """
    The following is documentation on how to use the class,
    without reference to the implementation details:

    For implementation notes, please see comments begining with `#`
    in the source file.

    [*crickets chirp*]

    """

    is_bad = lambda ch, baddies=baddies: return ch in baddies
    filter_baddies = lambda ch, *, is_bad=is_bad: "" if is_bad(ch) else ch
    mahp = replace_all.map(filter_baddies, line)
    return replace_all.join('', join(mahp))

    # -------------------------------------------------
    # WHY `baddies=baddies`?!?
    #     `is_bad=is_bad`
    # -------------------------------------------------
    # Default arguments to a lambda function are evaluated
    # at the same time as when a lambda function is
    # **defined**.
    #
    # global variables of a lambda function
    # are evaluated when the lambda function is
    # **called**
    #
    # The following prints "as yellow as snow"
    #
    #     fleece_color = "white"
    #     little_lamb = lambda end: return "as " + fleece_color + end
    #
    #     # sometime later...
    #
    #     fleece_color = "yellow"
    #     print(little_lamb(" as snow"))
    # --------------------------------------------------
replace_all.map = map
replace_all.join = str.join
Сэмюэл Малдун
источник
-1

Ниже один .. без использования концепции регулярных выражений ..

ipstring ="text with symbols!@#$^&*( ends here"
opstring=''
for i in ipstring:
    if i.isalnum()==1 or i==' ':
        opstring+=i
    pass
print opstring
Sadheesh
источник
-1

В Python 3.5

например,

os.rename(file_name, file_name.translate({ord(c): None for c in '0123456789'}))

Удалить все числа из строки

BonieSV
источник
-1

Вы можете использовать набор

    charlist = list(set(string.digits+string.ascii_uppercase) - set('10IO'))
    return ''.join([random.SystemRandom().choice(charlist) for _ in range(passlen)])
Сюй Чжэньлей
источник
Когда вы даете ответ, предпочтительно дать какое-то объяснение, ПОЧЕМУ ваш ответ тот.
Стивен Раух
-1

Рекурсивное разбиение: s = строка; символы = символы для удаления

def strip(s,chars):
if len(s)==1:
    return "" if s in chars else s
return strip(s[0:int(len(s)/2)],chars) +  strip(s[int(len(s)/2):len(s)],chars)

пример:

print(strip("Hello!","lo"))    #He!
матовый
источник
-1

# для каждого файла в каталоге переименовать имя файла

   file_list = os.listdir (r"D:\Dev\Python")

   for file_name in file_list:

       os.rename(file_name, re.sub(r'\d+','',file_name))
Роберт Сильва
источник
-1

Даже приведенный ниже подход работает

line = "a,b,c,d,e"
alpha = list(line)
        while ',' in alpha:
            alpha.remove(',')
finalString = ''.join(alpha)
print(finalString)

вывод: abcde

M2skills
источник
-2
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'
Арихант Бансал
источник
10
Удаляет только символы из начала или конца строки
divenex