Yes, you can use a regular expression for this:
import re
output = re.sub(r'\d+', '', '123hello 456world')
print output # 'hello world'
Answer from Martin Konecny on Stack OverflowYes, you can use a regular expression for this:
import re
output = re.sub(r'\d+', '', '123hello 456world')
print output # 'hello world'
str.translate should be efficient.
In [7]: 'hello467'.translate(None, '0123456789')
Out[7]: 'hello'
To compare str.translate against re.sub:
In [13]: %%timeit r=re.compile(r'\d')
output = r.sub('', my_str)
....:
100000 loops, best of 3: 5.46 µs per loop
In [16]: %%timeit pass
output = my_str.translate(None, '0123456789')
....:
1000000 loops, best of 3: 713 ns per loop
Videos
Would this work for your situation?
>>> s = '12abcd405'
>>> result = ''.join([i for i in s if not i.isdigit()])
>>> result
'abcd'
This makes use of a list comprehension, and what is happening here is similar to this structure:
no_digits = []
# Iterate through the string, adding non-numbers to the no_digits list
for i in s:
if not i.isdigit():
no_digits.append(i)
# Now join all elements of the list with '',
# which puts all of the characters together.
result = ''.join(no_digits)
As @AshwiniChaudhary and @KirkStrauser point out, you actually do not need to use the brackets in the one-liner, making the piece inside the parentheses a generator expression (more efficient than a list comprehension). Even if this doesn't fit the requirements for your assignment, it is something you should read about eventually :) :
>>> s = '12abcd405'
>>> result = ''.join(i for i in s if not i.isdigit())
>>> result
'abcd'
And, just to throw it in the mix, is the oft-forgotten str.translate which will work a lot faster than looping/regular expressions:
For Python 2:
from string import digits
s = 'abc123def456ghi789zero0'
res = s.translate(None, digits)
# 'abcdefghizero'
For Python 3:
from string import digits
s = 'abc123def456ghi789zero0'
remove_digits = str.maketrans('', '', digits)
res = s.translate(remove_digits)
# 'abcdefghizero'
You can use regex:
>>> import re
>>> strs = "c1309, IF1306, v1309, p1209, a1309, mo1309"
>>> re.sub(r'\d','',strs)
'c, IF, v, p, a, mo'
or a faster version:
>>> re.sub(r'\d+','',strs)
'c, IF, v, p, a, mo'
timeit comparisons:
>>> strs = "c1309, IF1306, v1309, p1209, a1309, mo1309"*10**5
>>> %timeit re.sub(r'\d','',strs)
1 loops, best of 3: 1.23 s per loop
>>> %timeit re.sub(r'\d+','',strs)
1 loops, best of 3: 480 ms per loop
>>> %timeit ''.join([c for c in strs if not c.isdigit()])
1 loops, best of 3: 1.07 s per loop
#winner
>>> %timeit from string import digits;strs.translate(None, digits)
10 loops, best of 3: 20.4 ms per loop
>>> text = 'mo1309'
>>> ''.join([c for c in text if not c.isdigit()])
'mo'
This is faster than regex
python -m timeit -s "import re; text = 'mo1309'" "re.sub(r'\d','',text)"
100000 loops, best of 3: 3.99 usec per loop
python -m timeit -s "import re; text = 'mo1309'" "''.join([c for c in text if not c.isdigit()])"
1000000 loops, best of 3: 1.42 usec per loop
python -m timeit -s "from string import digits; text = 'mo1309'" "text.translate(None, digits)"
1000000 loops, best of 3: 0.42 usec per loop
but str.translate as suggested by @DavidSousa:
from string import digits
text.translate(None, digits)
is always the fastest in stripping characters.
Also itertools supplies a little known function called ifilterfalse
>>> from itertools import ifilterfalse
>>> ''.join(ifilterfalse(str.isdigit, text))
'mo'
Instead of strip, select for the numbers with a regular expression:
import re
numbers = re.compile(r'\d+(?:\.\d+)?')
numbers.findall("It took 2.3 seconds")
Demo:
>>> import re
>>> numbers = re.compile(r'\d+(?:\.\d+)?')
>>> numbers.findall("It took 2.3 seconds")
['2.3']
This returns a list of all matches; this lets you find multiple numbers in a string too:
>>> numbers.findall("It took between 2.3 and 42.31 seconds")
['2.3', '42.31']
If all you want to do is remove all characters that aren't in another string, I'd suggest something like the following:
>>> to_filter = "It took 2.3 seconds"
>>> "".join(_ for _ in to_filter if _ in ".1234567890")
'2.3'
It's an extremely naive way to extract numbers, however. You should use the answer by Martijn Pieters if you want more than just a simple character filter like you asked for.
You can remove all digits, dots, dashes and spaces from the start using str.lstrip():
string1.lstrip('0123456789.- ')
The argument to str.strip() is treated as a set, e.g. any character at the start of the string that is a member of that set is removed until the string no longer starts with such characters.
Demo:
>>> samples = """\
... 123.123.This is a string some other numbers
... 1. This is a string some numbers
... 12-3-12.This is a string 123
... 123-12This is a string 1234
... """.splitlines()
>>> for sample in samples:
... print 'From: {!r}\nTo: {!r}\n'.format(
... sample, sample.lstrip('0123456789.- '))
...
From: '123.123.This is a string some other numbers'
To: 'This is a string some other numbers'
From: '1. This is a string some numbers'
To: 'This is a string some numbers'
From: '12-3-12.This is a string 123'
To: 'This is a string 123'
From: '123-12This is a string 1234'
To: 'This is a string 1234'
This is almost the same as @MartijnPieters' answer but we could use constants from string module if there are a lot of punctuation and whitespace characters to strip on top of digits:
import string
nonalpha = string.digits + string.punctuation + string.whitespace
out = some_string.lstrip(nonalpha)
So for the given sample:
for sample in [string1, string2, string3, string4]:
print('From: {!r}\nTo: {!r}\n'.format(sample, sample.lstrip(nonalpha)))
Output:
From: '123.123.This is a string some other numbers'
To: 'This is a string some other numbers'
From: '1. This is a string some numbers'
To: 'This is a string some numbers'
From: '12-3-12.This is a string 123'
To: 'This is a string 123'
From: '123-12This is a string 1234'
To: 'This is a string 1234'
>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
>>> # or
>>> re.sub(r"\D", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
Not sure if this is the most efficient way, but:
>>> ''.join(c for c in "abc123def456" if c.isdigit())
'123456'
The ''.join part means to combine all the resulting characters together without any characters in between. Then the rest of it is a generator expression, where (as you can probably guess) we only take the parts of the string that match the condition isdigit.
No, split would not work, because split only can work with a fixed string to split on.
You could use the str.rstrip() method:
import string
cleaned = yourstring.rstrip(string.digits)
This uses the string.digits constant as a convenient definition of what needs to be removed.
or you could use a regular expression to replace digits at the end with an empty string:
import re
cleaned = re.sub(r'\d+$', '', yourstring)
You can use str.rstrip with digit characters you want to remove trailing characters of the string:
>>> 'asdfg123'.rstrip('0123456789')
'asdfg'
Alternatively, you can use string.digits instead of '0123456789':
>>> import string
>>> string.digits
'0123456789'
>>> 'asdfg123'.rstrip(string.digits)
'asdfg'