232

I want to remove characters in a string in python:

string.replace(',', '').replace("!", '').replace(":", '').replace(";", '')...

But I have many characters I have to remove. I thought about a list

list = [',', '!', '.', ';'...]

But how can I use the list to replace the characters in the string?

georg
  • 211,518
  • 52
  • 313
  • 390
Laura
  • 4,199
  • 6
  • 23
  • 24
  • 6
    See http://stackoverflow.com/questions/1919096/mass-string-replace-in-python for various solutions and a nice comparison. – Martijn de Milliano Apr 04 '12 at 18:32
  • It's a pity that Python (which is said to come with batteries included) does not handle this use case out of the box. PHP's function str_replace does it - you can pass an array as the first argument and a string as the second (http://php.net/manual/pl/function.str-replace.php ). – JustAC0der Jan 13 '17 at 23:09

20 Answers20

280

If you're using python2 and your inputs are strings (not unicodes), the absolutely best method is str.translate:

>>> chars_to_remove = ['.', '!', '?']
>>> subj = 'A.B!C?'
>>> subj.translate(None, ''.join(chars_to_remove))
'ABC'

Otherwise, there are following options to consider:

A. Iterate the subject char by char, omit unwanted characters and join the resulting list:

>>> sc = set(chars_to_remove)
>>> ''.join([c for c in subj if c not in sc])
'ABC'

(Note that the generator version ''.join(c for c ...) will be less efficient).

B. Create a regular expression on the fly and re.sub with an empty string:

>>> import re
>>> rx = '[' + re.escape(''.join(chars_to_remove)) + ']'
>>> re.sub(rx, '', subj)
'ABC'

(re.escape ensures that characters like ^ or ] won't break the regular expression).

C. Use the mapping variant of translate:

>>> chars_to_remove = [u'δ', u'Γ', u'ж']
>>> subj = u'AжBδCΓ'
>>> dd = {ord(c):None for c in chars_to_remove}
>>> subj.translate(dd)
u'ABC'

Full testing code and timings:

#coding=utf8

import re

def remove_chars_iter(subj, chars):
    sc = set(chars)
    return ''.join([c for c in subj if c not in sc])

def remove_chars_re(subj, chars):
    return re.sub('[' + re.escape(''.join(chars)) + ']', '', subj)

def remove_chars_re_unicode(subj, chars):
    return re.sub(u'(?u)[' + re.escape(''.join(chars)) + ']', '', subj)

def remove_chars_translate_bytes(subj, chars):
    return subj.translate(None, ''.join(chars))

def remove_chars_translate_unicode(subj, chars):
    d = {ord(c):None for c in chars}
    return subj.translate(d)

import timeit, sys

def profile(f):
    assert f(subj, chars_to_remove) == test
    t = timeit.timeit(lambda: f(subj, chars_to_remove), number=1000)
    print ('{0:.3f} {1}'.format(t, f.__name__))

print (sys.version)
PYTHON2 = sys.version_info[0] == 2

print ('\n"plain" string:\n')

chars_to_remove = ['.', '!', '?']
subj = 'A.B!C?' * 1000
test = 'ABC' * 1000

profile(remove_chars_iter)
profile(remove_chars_re)

if PYTHON2:
    profile(remove_chars_translate_bytes)
else:
    profile(remove_chars_translate_unicode)

print ('\nunicode string:\n')

if PYTHON2:
    chars_to_remove = [u'δ', u'Γ', u'ж']
    subj = u'AжBδCΓ'
else:
    chars_to_remove = ['δ', 'Γ', 'ж']
    subj = 'AжBδCΓ'

subj = subj * 1000
test = 'ABC' * 1000

profile(remove_chars_iter)

if PYTHON2:
    profile(remove_chars_re_unicode)
else:
    profile(remove_chars_re)

profile(remove_chars_translate_unicode)

Results:

2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)]

"plain" string:

0.637 remove_chars_iter
0.649 remove_chars_re
0.010 remove_chars_translate_bytes

unicode string:

0.866 remove_chars_iter
0.680 remove_chars_re_unicode
1.373 remove_chars_translate_unicode

---

3.4.2 (v3.4.2:ab2c023a9432, Oct  5 2014, 20:42:22) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]

"plain" string:

0.512 remove_chars_iter
0.574 remove_chars_re
0.765 remove_chars_translate_unicode

unicode string:

0.817 remove_chars_iter
0.686 remove_chars_re
0.876 remove_chars_translate_unicode

(As a side note, the figure for remove_chars_translate_bytes might give us a clue why the industry was reluctant to adopt Unicode for such a long time).

georg
  • 211,518
  • 52
  • 313
  • 390
  • 4
    The second method raises an error `TypeError: translate() takes exactly one argument (2 given)`. Apparently it takes dict as an argument. – antonavy Sep 18 '14 at 13:02
  • @antonavy - the 2nd solution does work - but only of the string is not unicode (for which a different translate() is needed) – FuzzyAmi Dec 02 '14 at 13:50
120

You can use str.translate():

s.translate(None, ",!.;")

Example:

>>> s = "asjo,fdjk;djaso,oio!kod.kjods;dkps"
>>> s.translate(None, ",!.;")
'asjofdjkdjasooiokodkjodsdkps'
Noah
  • 21,451
  • 8
  • 63
  • 71
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 22
    @thg435: Nobody asked for this, but anyway: `s.translate(dict.fromkeys(map(ord, u",!.;")))` – Sven Marnach Apr 04 '12 at 18:43
  • 3
    This (and @PraveenGollakota's) [simultaneous answer](http://stackoverflow.com/a/10017200/623735) is exactly what @Laura asked for and should be the preferred answer(s). – hobs Jan 15 '14 at 07:07
  • 11
    why python3:TypeError: translate() takes exactly one argument (2 given) – Gank Sep 19 '15 at 10:27
  • 2
    @Gank: The `unicode.translate()` method has different parameters than the `str.translate()` method. Use the variant in the above comment for Unicode objects. – Sven Marnach Sep 19 '15 at 13:03
  • @SvenMarnach what is map(ord, u",!.;"))? and does u stand for unicode? – Jun Aug 23 '18 at 00:36
  • @Jun This maps the `ord()` function on all characters of the Unicode string `u",!.;"`, resulting in a list (Python 2) or an iterator (Python 3) of Unicode code points. The `u` denotes a Unicode string in Python 2. In Python 3 it's optional, since strings are Unicode strings by default (and early versions of Python 3 did not even support the `u""` syntax). – Sven Marnach Aug 23 '18 at 08:07
37

You can use the translate method.

s.translate(None, '!.;,')
Praveen Gollakota
  • 37,112
  • 11
  • 62
  • 61
35

If you are using python3 and looking for the translate solution - the function was changed and now takes 1 parameter instead of 2.

That parameter is a table (can be dictionary) where each key is the Unicode ordinal (int) of the character to find and the value is the replacement (can be either a Unicode ordinal or a string to map the key to).

Here is a usage example:

>>> list = [',', '!', '.', ';']
>>> s = "This is, my! str,ing."
>>> s.translate({ord(x): '' for x in list})
'This is my string'
Dekel
  • 60,707
  • 10
  • 101
  • 129
18
''.join(c for c in myString if not c in badTokens)
ninjagecko
  • 88,546
  • 24
  • 137
  • 145
11

Why not a simple loop?

for i in replace_list:
    string = string.replace(i, '')

Also, avoid naming lists 'list'. It overrides the built-in function list.

aIKid
  • 26,968
  • 4
  • 39
  • 65
9

Another approach using regex:

''.join(re.split(r'[.;!?,]', s))
alan
  • 4,752
  • 21
  • 30
6

you could use something like this

def replace_all(text, dic):
  for i, j in dic.iteritems():
    text = text.replace(i, j)
  return text

This code is not my own and comes from here its a great article and dicusses in depth doing this

krystan honour
  • 6,523
  • 3
  • 36
  • 63
5

simple way,

import re
str = 'this is string !    >><< (foo---> bar) @-tuna-#   sandwich-%-is-$-* good'

// condense multiple empty spaces into 1
str = ' '.join(str.split()

// replace empty space with dash
str = str.replace(" ","-")

// take out any char that matches regex
str = re.sub('[!@#$%^&*()_+<>]', '', str)

output:

this-is-string--foo----bar--tuna---sandwich--is---good

Dhia
  • 10,119
  • 11
  • 58
  • 69
perfecto25
  • 772
  • 9
  • 13
4

Also an interesting topic on removal UTF-8 accent form a string converting char to their standard non-accentuated char:

What is the best way to remove accents in a python unicode string?

code extract from the topic:

import unicodedata

def remove_accents(input_str):
    nkfd_form = unicodedata.normalize('NFKD', input_str)
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
Community
  • 1
  • 1
Sylvain
  • 336
  • 2
  • 7
4

Perhaps a more modern and functional way to achieve what you wish:

>>> subj = 'A.B!C?'
>>> list = set([',', '!', '.', ';', '?'])
>>> filter(lambda x: x not in list, subj)
'ABC'

please note that for this particular purpose it's quite an overkill, but once you need more complex conditions, filter comes handy

rioted
  • 1,076
  • 13
  • 24
  • Also note that this can just as easily be done with list comprehensions, which is way more pythonic in my opinion. – rioted Nov 15 '16 at 11:47
4

Remove *%,&@! from below string:

s = "this is my string,  and i will * remove * these ** %% "
new_string = s.translate(s.maketrans('','','*%,&@!'))
print(new_string)

# output: this is my string  and i will  remove  these  
Biplob Das
  • 2,818
  • 21
  • 13
  • Explanation: 1. maketrans(x,y,z): the third parameter is for replace. x,y are '' here, so makes no change. Only characters with z are removed 2. translate(): returns a string where each character is mapped to its corresponding character in the translation table (here from the maketrans fn) – Aybid Oct 18 '20 at 03:01
2

How about this - a one liner.

reduce(lambda x,y : x.replace(y,"") ,[',', '!', '.', ';'],";Test , ,  !Stri!ng ..")
Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
2

i think this is simple enough and will do!

list = [",",",","!",";",":"] #the list goes on.....

theString = "dlkaj;lkdjf'adklfaj;lsd'fa'dfj;alkdjf" #is an example string;
newString="" #the unwanted character free string
for i in range(len(TheString)):
    if theString[i] in list:
        newString += "" #concatenate an empty string.
    else:
        newString += theString[i]

this is one way to do it. But if you are tired of keeping a list of characters that you want to remove, you can actually do it by using the order number of the strings you iterate through. the order number is the ascii value of that character. the ascii number for 0 as a char is 48 and the ascii number for lower case z is 122 so:

theString = "lkdsjf;alkd8a'asdjf;lkaheoialkdjf;ad"
newString = ""
for i in range(len(theString)):
     if ord(theString[i]) < 48 or ord(theString[i]) > 122: #ord() => ascii num.
         newString += ""
     else:
        newString += theString[i]
2

In Python 3.8, this works for me:

s.translate(s.maketrans(dict.fromkeys(',!.;', '')))
  • [str.translate()](https://docs.python.org/2/library/stdtypes.html#str.translate) is from python2 and there is no need to use maketrans() func. – confiq Dec 03 '21 at 16:05
  • 1
    @config on the contrary: python 3 has a [`str.translate()`](https://docs.python.org/3/library/stdtypes.html#str.translate) which takes char ords, and thus *does* require something like [`str.maketrans()`](https://docs.python.org/3/library/stdtypes.html#str.translate) (or ee.g. a dict comp calling `ord` as in the other python3 answer).. This answer won't work without the `maketrans()` (try it). – 2e0byo Dec 03 '21 at 19:02
1

These days I am diving into scheme, and now I think am good at recursing and eval. HAHAHA. Just share some new ways:

first ,eval it

print eval('string%s' % (''.join(['.replace("%s","")'%i for i in replace_list])))

second , recurse it

def repn(string,replace_list):
    if replace_list==[]:
        return string
    else:
        return repn(string.replace(replace_list.pop(),""),replace_list)

print repn(string,replace_list)

Hey ,don't downvote. I am just want to share some new idea.

tcpiper
  • 2,456
  • 2
  • 28
  • 41
1

I am thinking about a solution for this. First I would make the string input as a list. Then I would replace the items of list. Then through using join command, I will return list as a string. The code can be like this:

def the_replacer(text):
    test = []    
    for m in range(len(text)):
        test.append(text[m])
        if test[m]==','\
        or test[m]=='!'\
        or test[m]=='.'\
        or test[m]=='\''\
        or test[m]==';':
    #....
            test[n]=''
    return ''.join(test)

This would remove anything from the string. What do you think about that?

Sheikh Ahmad Shah
  • 281
  • 1
  • 4
  • 12
1

Here is a more_itertools approach:

import more_itertools as mit


s = "A.B!C?D_E@F#"
blacklist = ".!?_@#"

"".join(mit.flatten(mit.split_at(s, pred=lambda x: x in set(blacklist))))
# 'ABCDEF'

Here we split upon items found in the blacklist, flatten the results and join the string.

pylang
  • 40,867
  • 14
  • 129
  • 121
1

Python 3, single line list comprehension implementation.

from string import ascii_lowercase # 'abcdefghijklmnopqrstuvwxyz'
def remove_chars(input_string, removable):
  return ''.join([_ for _ in input_string if _ not in removable])

print(remove_chars(input_string="Stack Overflow", removable=ascii_lowercase))
>>> 'S O'
John Forbes
  • 1,248
  • 14
  • 19
1

Why not utilize this simple function:

def remove_characters(str, chars_list):
    for char in chars_list:
        str = str.replace(char, '')
  
    return str

Use function:

print(remove_characters('A.B!C?', ['.', '!', '?']))

Output:

ABC
Shaida Muhammad
  • 1,428
  • 14
  • 25