如何在Python中删除字符串中的所有非数字字符?


当前回答

这应该适用于Python2中的字符串和unicode对象,以及Python3中的字符串和字节:

# python <3.0
def only_numerics(seq):
    return filter(type(seq).isdigit, seq)

# python ≥3.0
def only_numerics(seq):
    seq_type= type(seq)
    return seq_type().join(filter(seq_type.isdigit, seq))

其他回答

@Ned Batchelder和@newacct给出了正确答案,但是…

以防万一,如果你的字符串中有逗号(,)decimal(.):

import re
re.sub("[^\d\.]", "", "$1,999,888.77")
'1999888.77'

一个简单的方法:

str.isdigit()如果str只包含数字字符则返回True。调用filter(predicate, iterable),将str.isdigit作为谓词,将字符串作为迭代对象,返回一个只包含字符串的数字字符的迭代对象。调用str.join(iterable),将空字符串作为str,将filter()的结果作为iterable,将每个数字字符连接到一个字符串中。

例如:

a_string = "!1a2;b3c?"
numeric_filter = filter(str.isdigit, a_string)
numeric_string = "".join(numeric_filter)
print(numeric_string)

输出为:

123

不确定这是否是最有效的方法,但是:

>>> ''.join(c for c in "abc123def456" if c.isdigit())
'123456'

”。连接部分是指将所有产生的字符组合在一起,中间没有任何字符。然后它的其余部分是一个生成器表达式,其中(正如您可能猜到的那样)我们只取字符串中与条件isdigit匹配的部分。

这里有很多正确答案。有些比其他的快或慢。在Ehsan Akbaritabar和tot的答案中使用的方法,str.isdigit过滤,非常快;正如翻译,从亚历克斯·马特利的回答,一旦设置完成。这是两种最快的方法。但是,如果您只做一次替换,那么转换的设置代价将非常大。

哪种方式是最好的取决于您的用例。单元测试中的一个替换?我将使用isdigit进行筛选。它不需要导入,只使用内置,并且快速简单:

''.join(filter(str.isdigit, string_to_filter))

在pandas或pyspark DataFrame中,有数百万行,如果不使用DataFrame提供的方法(往往依赖于regex),那么翻译的效率可能是值得的。

如果你想使用翻译方法,我建议在Python 3中做一些更改:

import string

unicode_non_digits = dict.fromkeys(
    [x for x in range(65536) if chr(x) not in string.digits]
)
string_to_filter.translate(unicode_non_digits)
Method Loops Repeats Best of result per loop
filter using isdigit 1000 15 0.83 usec
generator using isdigit 1000 15 1.6 usec
using re.sub 1000 15 1.94 usec
generator testing membership in digits 1000 15 1.23 usec
generator testing membership in digits set 1000 15 1.19 usec
use translate 1000 15 0.797 usec
use re.compile 1000 15 1.52 usec
use translate but make translation table every time 20 5 1.21e+04 usec

表中的最后一行显示翻译的设置惩罚。每次创建翻译表时,我都使用默认的数字和重复选项,否则会花费太长时间。

从我的计时脚本的原始输出:

/bin/zsh /Users/henry.longmore/Library/Application\ Support/JetBrains/PyCharm2022.2/scratches/scratch_4.sh
+/Users/henry.longmore/Library/Application Support/JetBrains/PyCharm2022.2/scratches/scratch_4.sh:6> which python
/Users/henry.longmore/.pyenv/shims/python
+/Users/henry.longmore/Library/Application Support/JetBrains/PyCharm2022.2/scratches/scratch_4.sh:7> python --version
Python 3.10.6
+/Users/henry.longmore/Library/Application Support/JetBrains/PyCharm2022.2/scratches/scratch_4.sh:8> set +x
-----filter using isdigit
1000 loops, best of 15: 0.83 usec per loop
-----generator using isdigit
1000 loops, best of 15: 1.6 usec per loop
-----using re.sub
1000 loops, best of 15: 1.94 usec per loop
-----generator testing membership in digits
1000 loops, best of 15: 1.23 usec per loop
-----generator testing membership in digits set
1000 loops, best of 15: 1.19 usec per loop
-----use translate
1000 loops, best of 15: 0.797 usec per loop
-----use re.compile
1000 loops, best of 15: 1.52 usec per loop
-----use translate but make translation table every time
     using default number and repeat, otherwise this takes too long
20 loops, best of 5: 1.21e+04 usec per loop

我用于计时的脚本:

NUMBER=1000
REPEAT=15
UNIT="usec"
TEST_STRING="abc123def45ghi6789"
set -x
which python
python --version
set +x
echo "-----filter using isdigit"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT "''.join(filter(str.isdigit, '${TEST_STRING}'))"
echo "-----generator using isdigit"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT "''.join(c for c in '${TEST_STRING}' if c.isdigit())"
echo "-----using re.sub"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT --setup="import re" "re.sub('[^0-9]', '', '${TEST_STRING}')"
echo "-----generator testing membership in digits"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT --setup="from string import digits" "''.join(c for c in '${TEST_STRING}' if c in digits)"
echo "-----generator testing membership in digits set"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT --setup="from string import digits; digits = {*digits}" "''.join(c for c in '${TEST_STRING}' if c in digits)"
echo "-----use translate"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT --setup="import string; unicode_non_digits = dict.fromkeys([x for x in range(65536) if chr(x) not in string.digits])" "'${TEST_STRING}'.translate(unicode_non_digits)"
echo "-----use re.compile"
python -m timeit --number=$NUMBER --repeat=$REPEAT --unit=$UNIT --setup="import re; digit_filter = re.compile('[^0-9]')" "digit_filter.sub('', '${TEST_STRING}')"
echo "-----use translate but make translation table every time"
echo "     using default number and repeat, otherwise this takes too long"
python -m timeit --unit=$UNIT --setup="import string" "unicode_non_digits = dict.fromkeys([x for x in range(65536) if chr(x) not in string.digits]); '${TEST_STRING}'.translate(unicode_non_digits)"


>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'