Pythonを使用して文字列から数字以外の文字を削除しますか?


137

文字列から数字以外のすべての文字を削除するにはどうすればよいですか?


@Jan Tojnar:例を挙げていただけますか?
ジョアン・シルバ

@JG:私はgtk.Entry()を持っており、そこに乗算浮動小数点数を入力したい。
Jan Tojnar、2009年

1
@JanTojnarは回答2に従ってre.subメソッドを使用し、保持する文字を明示的にリストします。たとえば、re.sub( "[^ 0123456789 \。]"、 ""、 "poo123.4and5fish")
Roger Heathcote

回答:


112

Python 2. *では、最も速いアプローチは.translateメソッドです。

>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>> 

string.maketrans変換テーブル(長さ256の文字列)を作成します。この場合、''.join(chr(x) for x in range(256))(作成するのがより速い;-) と同じです。.translate変換テーブル(all基本的にはIDを意味するため、ここでは関係ありません)を適用し、2番目の引数(キー部分)にある文字を削除します。

.translateUnicode文字列(およびPython 3の文字列)ではまったく異なる動作をしますメジャーリリースに関心があるを質問に明記して!)-非常に単純ではありませんが、それほど高速ではありませんが、まだかなり使用可能です。

2. *に戻ると、パフォーマンスの違いは印象的です...:

$ python -mtimeit -s'import string; all=string.maketrans("", ""); nodig=all.translate(all, string.digits); x="aaa12333bb445bb54b5b52"' 'x.translate(all, nodig)'
1000000 loops, best of 3: 1.04 usec per loop
$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 7.9 usec per loop

物事を7-8倍高速化することはほとんどピーナッツではないので、このtranslate方法は知って使用する価値があります。他の一般的な非REアプローチ...:

$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop

REはREより50%遅いため、.translateアプローチはそれを1桁以上上回ります。

Python 3では、またはUnicodeの場合、削除するもの.translateに対して返すマッピング(キーではなく、文字ではなく序数を使用)を渡す必要がありNoneます。これは、「すべてを除く」数文字を削除するためにこれを表現する便利な方法です。

import string

class Del:
  def __init__(self, keep=string.digits):
    self.comp = dict((ord(c),c) for c in keep)
  def __getitem__(self, k):
    return self.comp.get(k)

DD = Del()

x='aaa12333bb445bb54b5b52'
x.translate(DD)

も放出し'1233344554552'ます。しかし、これをxx.pyに入れると...:

$ python3.1 -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 8.43 usec per loop
$ python3.1 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
10000 loops, best of 3: 24.3 usec per loop

...この種の「削除」タスクでは、パフォーマンスの利点が失われ、パフォーマンスが低下することを示しています。


1
@sunqiang、はい、絶対に-Py3kがPy2のようにバイト文字列ではなく、テキスト文字列型としてUnicodeに移行した理由があります-同じ理由JavaとC#は常に同じ「文字列はユニコードを意味する」ミームを持っていました...オーバーヘッドもあるかもしれませんが、英語以外のサポートがかなり充実しています!-)。
Alex Martelli、

29
x.translate(None, string.digits)実際の結果は'aaabbbbbb'、意図したものとは逆になります。
トムダリング

4
トムダリングからのコメントをエコーすると、最初の例ではすべての望ましくない文字が保持されます。
Chris Johnson

3
@ RyanB.Lynchら、後の編集者と、その編集承認した他の2人のユーザーに障害がありましたが、実際には完全に間違っています。元に戻しました。
Nick T

1
all組み込みをオーバーライドしています...それについては不明です!
Andy Hayden 2013年

197

次のre.subように使用します:

>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'

\D 数字以外の文字に一致するので、上記のコードは基本的に、空の文字列の数字以外のすべての文字を置き換えます。

またはfilter、次のように使用できます(Python 2の場合):

>>> filter(str.isdigit, 'aas30dsa20')
'3020'

Python 3 filterではの代わりにイテレータを返すため、代わりにlist次のコードを使用できます。

>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'

reはそのような単純なタスクでは悪であり、2番目のタスクは私が考える最高のものです。
f0b0s 09/09/20

フィルターの例はpy2kに制限されています
SilentGhost

2
@ f0b0s-iu9-info:計時しましたか?私のマシン(py3k)では、reはwith with filterの2倍の速さでisdigit、ジェネレーターisdigtはその中間にあります
SilentGhost

@SilentGhost:ありがとう、py2kのIDLEを使用していました。現在は修正されています。
ジョアン・シルバ

1
@asmaierそのままのr文字列に使用する:re.sub(r"\D+", "", "aas30dsa20")
Mitch McMabers

64
s=''.join(i for i in s if i.isdigit())

別のジェネレーターバリアント。


Killed it .. + 1ラムダが使用されていればさらに良かったでしょう
Barath Ravikumar

17

フィルターを使用できます:

filter(lambda x: x.isdigit(), "dasdasd2313dsa")

python3.0では、これに参加する必要があります(ちょっと醜い:()

''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))

py2kでのみ、py3kでジェネレータを返します
SilentGhost

py2とpy3の両方で機能することを確認するstrためlistに変換します。– ''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
Luiz C.


12

あなたはRegexを使って簡単にそれを行うことができます

>>> import re
>>> re.sub("\D","","£70,000")
70000

はるかに簡単な方法
Iorek

5
これは、7年前に提供されたJoãoSilvaの回答とどう違うのですか?
jww

7
x.translate(None, string.digits)

文字列からすべての数字を削除します。文字を削除して数字を保持するには、次のようにします。

x.translate(None, string.letters)

3
私はTypeError:translate()が引数を1つだけ受け取ります(2つ与えられます)。この質問が現在の状態で賛成された理由は非常にイライラします。
Bobort 2016年

translateがpython 2から3に変更されました。このメソッドをpython 3で使用する構文は、x.translate(str.maketrans( ''、 ''、string.digits))およびx.translate(str.maketrans( ''、 ''です。 、string.ascii_letters))。これらはどちらも空白を取り除きません。私はもうこのアプローチをお勧めしません...
ZaxR '16

5

opはコメントで彼が小数点以下を保持したいと述べています。これは、保持する文字を明示的にリストすることで、re.subメソッド(2番目およびIMHOベストアンサーに従って)で実行できます。

>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'

「poo123.4and.5fish」はどうですか?
Jan Tojnar 2013

私のコードでは、入力文字列のピリオドの数を確認し、それが1より大きい場合はエラーを発生させます
Roger Heathcote

4

Python 3の高速バージョン:

# xx3.py
from collections import defaultdict
import string
_NoneType = type(None)

def keeper(keep):
    table = defaultdict(_NoneType)
    table.update({ord(c): c for c in keep})
    return table

digit_keeper = keeper(string.digits)

次に、正規表現とパフォーマンスの比較を示します。

$ python3.3 -mtimeit -s'import xx3; x="aaa12333bb445bb54b5b52"' 'x.translate(xx3.digit_keeper)'
1000000 loops, best of 3: 1.02 usec per loop
$ python3.3 -mtimeit -s'import re; r = re.compile(r"\D"); x="aaa12333bb445bb54b5b52"' 'r.sub("", x)'
100000 loops, best of 3: 3.43 usec per loop

ですから、私にとっては正規表現よりも3倍以上高速です。また、class Del上記よりも高速です。defaultdict(遅い)Pythonではなく、すべてのルックアップをCで行うです。比較のために、同じシステムでのそのバージョンを以下に示します。

$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop

3

ジェネレータ式を使用します。

>>> s = "foo200bar"
>>> new_s = "".join(i for i in s if i in "0123456789")

代わりに''.join(n for n in foo if n.isdigit())
shxfee

2

醜いが動作します:

>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>

なんでlist(s)
SilentGhost 2009

@SilentGhostそれは私の誤解です。おかげで修正されました:)
Gant

実際、この方法では、「結合」を使用する必要はないと思います。 filter(lambda x: x.isdigit(), s)私にとってはうまくいきました。...ああ、それは私がPython 2.7を使用しているためです。
Bobort 2016年

1
$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000ループ、ベスト3:ループあたり2.48 usec

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000ループ、ベスト3:ループあたり2.02 usec

$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000ループ、3つのうちの2.37ループあたり2.37 usec

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000ループ、最高3:ループあたり1.97 usec

結合はサブよりも速いことを観察しました。


2つの方法を2回繰り返すのはなぜですか。そして、あなたの答えは受け入れられたものとどのように違うのですか?
Jan Tojnar 2018

どちらも同じ出力になります。ただし、結果のサブメソッドの方が結合が速いことを示したいだけです。
AnilReddy

彼らはしません、あなたのコードは反対です。また、4つの測定がありますが、2つの方法しかありません。
Jan Tojnar 2018

1

あなたは各文字を読むことができます。数字の場合は、回答に含めてください。str.isdigit() この方法は、文字が数字であるかどうかを知るための方法です。

your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'

これはf0b0sの回答とどう違うのですか?あなたが持って来るために多くの情報を持っている場合は、代わりにその答えを編集する必要があります
chevybow

0

ワンライナーではありませんが、非常にシンプルです:

buffer = ""
some_str = "aas30dsa20"

for char in some_str:
    if not char.isdigit():
        buffer += char

print( buffer )

0

私はこれを使いました。'letters'あなたが取り除きたいすべての文字を含む必要があります:

Output = Input.translate({ord(i): None for i in 'letters'}))

例:

Input = "I would like 20 dollars for that suit" Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'})) print(Output)

出力: 20

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.