从字符串中提取数字

16
我们有一些字符串,例如:c1309IF1306v1309p1209a1309mo1309
在Python中,最好的方法是什么来剥离出这些数字?我只需要从上面的例子中得到:cIFvpamo

14
为什么这个简单的问题会得到这么多赞 o_O? 而且人们可以只需要搜索并使用这个问题的“反向”解决方案。 - HamZa
4
简单的问题更容易得到赞同,因为所有用户,甚至那些不熟悉该语言的用户都可以轻松快速地观察到它们。 - jamylak
@jamylak 有些悲伤,说实话有点嫉妒... - HamZa
5
@HamZa 这很简单,只需要使用Python中的切片操作即可。下面是一行代码示例:reversed_string = original_string[::-1] - jamylak
@jamylak 哈哈哈哈,我要学习Python! - HamZa
2
@HamZa 这就是独裁者在小事上强行干预的问题。 - Mike G
8个回答

27
你可以使用正则表达式:
>>> import re
>>> strs = "c1309, IF1306, v1309, p1209, a1309, mo1309"
>>> re.sub(r'\d','',strs)
'c, IF, v, p, a, mo'

或者更快的版本:

>>> re.sub(r'\d+','',strs)
'c, IF, v, p, a, mo'

timeit比较:

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

1
最好使用re.sub(r'\d+','',strs),以提高效率。 - Tim Pietzcker
1
@TimPietzcker 谢谢,我以前不知道这个。 - Ashwini Chaudhary
如果数字只是十进制的,那么 re.sub(r'[0-9]+','',strs) 会提高速度吗? - Grijesh Chauhan
@GrijeshChauhan:可能不会,或者至少不会有显著的影响,除非您使用're.UNICODE'编译正则表达式。 - Tim Pietzcker

22
>>> text = 'mo1309'
>>> ''.join([c for c in text if not c.isdigit()])
'mo'

这比正则表达式更快

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

但是,正如@DavidSousa建议的那样,使用str.translate

from string import digits
text.translate(None, digits)

在去除字符方面,它始终是最快的。

itertools 还提供了一个鲜为人知的函数 ifilterfalse

>>> from itertools import ifilterfalse
>>> ''.join(ifilterfalse(str.isdigit, text))
'mo'

使用列表推导式的 join 比使用生成器表达式的 join 更快吗? - Blender
对于大字符串来说,它们几乎是等价的。 - Ashwini Chaudhary
1
@Blender https://dev59.com/AWox5IYBdhLWcg3wpV_F#9061024 - Ashwini Chaudhary

13

我认为字符串方法translate比拼接列表等更加优雅。

from string import digits # digits = '0123456789'
list1 = ['c1309', 'IF1306', 'v1309', 'p1209', 'a1309', 'mo1309']
list2 = [ i.translate(None, digits) for i in list1 ]

2
from string import digits 更好(不确定为什么你改了它)。这是在Python 2中最快的方法,可能在Python 3中更优雅的方式是:text.translate(str.maketrans('', '', digits)) - jamylak
1
+1 但你可以使用列表推导式使其更加优雅。 - Jan Wrobel
@jamylak 我只是为了更清晰而进行了修改。 - David Sousa

3

我认为这是最简单的方法,也可能是最快的方法。

>>> import string
>>> s = 'c1309, IF1306, v1309, p1209, a1309, mo1309'
>>> s.translate(None, string.digits)
'c, IF, v, p, a, mo'

注意:在Python3中,str.translate的接口已更改为使用映射,因此以下是适用于Python3的版本。
s.translate({ord(n): None for n in string.digits})

或者更明确的替代方案:
m = str.maketrans('', '', string.digits)
s.translate(m)

1
strings = ['c1309', 'IF1306', 'v1309', 'p1209', 'a1309', 'mo1309']
stripped = [''.join(c for c in s if not c.isdigit()) for s in strings]

1
如果您要处理的所有字符串都以数字结尾,那么您可以“字面上”地剥离该数字:
>>> strings = ['c1309', 'IF1306', 'v1309', 'p1209', 'a1309', 'mo1309']
>>> [s.strip("0123456789") for s in strings]
['c', 'IF', 'v', 'p', 'a', 'mo']

如果您只想删除字符串末尾的数字,请使用rstrip。如果数字可能出现在字符串中,则此方法将无法起作用。

+1。这可能是OP所需要的全部内容。您还可以将解决方案中的0123456789替换为string.digits - iruvar

0

如果数字长度固定且位置不在字符串中间,请使用切片符号。

NUM_LEN = 4
stringsWithDigit = ["ab1234", "cde1234", "fgh5678"]
for i in stringsWithDigit:
   print i[:-NUM_LEN]

任何其他东西
import re
c = re.compile("[^0-9]+")
print c.findall("".join(stringsWithDigit))

0
你可以尝试使用这个正则表达式:
^[a-zA-Z]+

它将仅获取字符串中连续的字母从开头开始,并忽略所有其他内容。

不需要进行替换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接