Видаліть конкретні символи з рядка в Python


546

Я намагаюся видалити конкретні символи з рядка за допомогою 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

Відповіді:


625

Рядки в 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 '!@#$'})
naveen

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, '!@#$')))
Martijn Pieters

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"

26
Це зробить копію рядка в кожному циклі, що може виявитися небажаним. Крім того, це не дуже добре Python. У Python вам слід замість цього циклу:for char in b: a=a.replace(char,"")
elgehelge

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'

використовуйте інший роздільник рядків, наприклад "" "або"
ALisboa

1
Якщо у вас є багато заборонених символів, ви можете пришвидшити свій код, перетворивши його в набір спочатку. blacklist = set('?:!/;')а потім''.join(c for c in line if c not in blacklist)
Борис

32

Легкий горошок з 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'

З документації щодо регулярного вираження пітона :

Символи, які не знаходяться в межах діапазону, можна зіставити, доповнивши набір. Якщо перший символ набору є '^', всі символи, які відсутні в наборі, будуть збігатися. Наприклад, [^5]буде відповідати будь-якому символу , крім «5», і [^^]буде відповідати будь-якому символу , за винятком '^'. ^не має особливого значення, якщо це не перший персонаж у наборі.


19

У аскера це майже не було. Як і більшість речей у Python, відповідь простіша, ніж ви думаєте.

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

Вам не доведеться робити вкладені речі if / for циклу, але НЕ потрібно перевіряти кожен символ окремо.


так, я знаю, напевно, пізно, але треба працювати, якщо уникнути цього. Ось так: line = line.replace ('' ',' ') читати далі: learnpythonthehardway.org/book/ex10.html
Aiyion.Prime

Це, ймовірно, не є виконавцем, оскільки ви виділяєте нову рядок для кожного символу
OneCricketeer


11
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'

2
Моя відповідь дає змогу вирішити оригінальне запитання, але мене також зацікавили (можливо, і ОП) відгуки щодо того, чому моє рішення може бути не ідеальним. Чи повинен я створити нове запитання і вказати це на контекст?
eatkin

Це отримує мій голос. Python лаконічний
Стів

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()])

Це воно. Поверненням буде рядок усіх символів, які є цифрами в початковому рядку.

Якщо у вас є певний список прийнятних / неприйнятних символів, вам потрібно лише відкоригувати частину 'if' для розуміння списку.

      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, або якщо ви намагаєтеся перевірити рівень С, 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.

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" - це іспанське слово, щоб сказати bat ... смішне слово, оскільки воно містить усі голосні :)

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 є найшвидшою для цього конкретного введення.


1
Ви створюєте непотрібне list в attempt1і кортеж може бути переписаний "aeiou"для простоти користі (видалення [і ]перетворитеся на в генератор без створення списку). Ви створюєте тонни посередницьких рядків attemt2, що викидаються , ви використовуєте кілька застосувань регулярного вираження, attempt3де ви могли б використовуватись r'[aeiou]'за один прохід. у кожного є вади - приємно бачити різні способи робити речі, але, будь ласка, зафіксуйте їх, щоб вони також були хорошими спробами
Патрік Артнер

1
@PatrickArtner Ви абсолютно праві ... з десятків способів, які я маю на увазі, щоб досягти цього завдання, я підібрав повільніші (хотів показати ОП кілька найпростіших) ... Це сказав, після вас хлопці закрили іншу тему, я втратив мотивацію докласти більше зусиль на цю вже відповів стару тему, так що ... :) Дякую за очки, хоча.
BPL

@PatrickArtner Добре ... просто заради ради додав новий, "спроба4" ... не вимірював, але я думаю, що треба бути швидшим
BPL

1
@PatrickArtner Відредаговано ... спроба4 була найшвидшою з невеликого набору спроб. У всякому разі, я не витрачаю більше часу на цей матеріал :)
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, '!@#$'))створив карту.
Martijn Pieters

mapяк правило, менш читабельна, ніж розуміння списку / диктантів / наборів / генераторів. Настільки, що Гвідо хотів зняти його з мови . Використання 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

1
Не могли б ви детальніше розглянути свою відповідь, додавши трохи більше опису про рішення, яке ви надаєте?
аборисон

Якщо додати до списку, то використання приєднання було б більш ефективним, ніж конкатенація
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

1

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

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

Це призведе до "видалення", утримуючи слово "це".

Форматування може бути дуже корисним для друку змінних посередині через рядок друку. Він може вставити будь-який тип даних, використовуючи %, а за ним тип даних змінної; всі типи даних можуть використовувати % s , а floats (також десяткові числа) та цілі числа можуть використовувати % d .

Нарізка може використовуватися для хитромудрого контролю над рядками. Коли я кладу слова [: 3] , це дозволяє мені вибирати всі символи в рядку від початку (двокрапка - перед числом, це буде означати "від початку до") до 4-го символу (він включає 4 персонаж). Причина 3 дорівнює 4-й позиції, тому що Python починається з 0. Потім, коли я кладу слово [-1:] , це означає другий останній символ до кінця (двокрапка знаходиться за цифрою). Якщо поставити -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 , тому вам також знадобиться.


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

Ви можете використовувати заміну регулярного виразу повторного модуля. Використання виразу ^ дозволяє вибрати саме те, що ви хочете зі свого рядка.

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

Вихід до цього буде "Thisisabsurd". З'являться лише речі, вказані після символу ^.


0

Метод string 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

-1

У Python 3.5

наприклад,

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

Щоб видалити все число з рядка



-1

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

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


-2
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'

10
Видаляє символи лише з початку або в кінці рядка
divenex
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.