web-dev-qa-db-ja.com

Pythonで文字列から数字を抽出する方法は?

文字列に含まれるすべての数字を抽出します。目的、正規表現、isdigit()メソッドのどちらに適していますか?

例:

line = "hello 12 hi 89"

結果:

[12, 89]
335
pablouche

正の整数のみを抽出したい場合は、次のことを試してください。

>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]

私はこれが三つの理由で正規表現の例より良いと主張するでしょう。まず、他のモジュールは必要ありません。次に、正規表現ミニ言語を解析する必要がないため、読みやすくなります。そして第三に、それは速い(そしておそらくPythonic)でしょう:

python -m timeit -s "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "[s for s in str.split() if s.isdigit()]"
100 loops, best of 3: 2.84 msec per loop

python -m timeit -s "import re" "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "re.findall('\\b\\d+\\b', str)"
100 loops, best of 3: 5.66 msec per loop

浮動小数点数、負の整数、または16進形式の整数は認識されません。あなたがこれらの制限を受け入れることができないならば、 以下のスリムな答え はうまくいくでしょう。

383
fmark

私は正規表現を使用したいと思います:

>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']

これはbla42blaの42にも一致します。単語の境界(スペース、ピリオド、コンマ)で区切られた数字だけが必要な場合は、\ bを使用できます。

>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']

文字列のリストではなく数字のリストになるには、次のようにします。

>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]
364
Vincent Savard

これは少し遅くなりますが、科学的表記法を説明するために正規表現を拡張することができます。

import re

# Format is [(<string>, <expected output>), ...]
ss = [("Apple-12.34 ba33na fanc-14.23e-2yapple+45e5+67.56E+3",
       ['-12.34', '33', '-14.23e-2', '+45e5', '+67.56E+3']),
      ('hello X42 I\'m a Y-32.35 string Z30',
       ['42', '-32.35', '30']),
      ('he33llo 42 I\'m a 32 string -30', 
       ['33', '42', '32', '-30']),
      ('h3110 23 cat 444.4 rabbit 11 2 dog', 
       ['3110', '23', '444.4', '11', '2']),
      ('hello 12 hi 89', 
       ['12', '89']),
      ('4', 
       ['4']),
      ('I like 74,600 commas not,500', 
       ['74,600', '500']),
      ('I like bad math 1+2=.001', 
       ['1', '+2', '.001'])]

for s, r in ss:
    rr = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", s)
    if rr == r:
        print('GOOD')
    else:
        print('WRONG', rr, 'should be', r)

すべてがいい!

さらに、 AWS Glueに組み込まれている正規表現を見ることもできます

私はあなたが整数だけではなく浮動小数点数が欲しいと思っているので、私はこのような何かをしたいと思います:

l = []
for t in s.split():
    try:
        l.append(float(t))
    except ValueError:
        pass

ここに掲載されている他の解決策のいくつかは負の数では動作しないことに注意してください。

>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string -30')
['42', '32', '30']

>>> '-3'.isdigit()
False
61
jmnas

それが文字列の中の1つの数字、すなわち 'hello 12 hi'だけになることがわかっているなら、あなたはfilterを試すことができます。

例えば:

In [1]: int(''.join(filter(str.isdigit, '200 grams')))
Out[1]: 200
In [2]: int(''.join(filter(str.isdigit, 'Counters: 55')))
Out[2]: 55
In [3]: int(''.join(filter(str.isdigit, 'more than 23 times')))
Out[3]: 23

しかし気をつけて! :

In [4]: int(''.join(filter(str.isdigit, '200 grams 5')))
Out[4]: 2005
48
dfostic
# extract numbers from garbage string:
s = '12//n,[email protected]#$%3.14kjlw0xdadfackvj1.6e-19&*ghn334'
newstr = ''.join((ch if ch in '0123456789.-e' else ' ') for ch in s)
listOfNumbers = [float(i) for i in newstr.split()]
print(listOfNumbers)
[12.0, 3.14, 0.0, 1.6e-19, 334.0]
9
AndreiS

この回答には、数値が文字列内でfloatの場合も含まれます。

def get_first_nbr_from_str(input_str):
    '''
    :param input_str: strings that contains digit and words
    :return: the number extracted from the input_str
    demo:
    'ab324.23.123xyz': 324.23
    '.5abc44': 0.5
    '''
    if not input_str and not isinstance(input_str, str):
        return 0
    out_number = ''
    for ele in input_str:
        if (ele == '.' and '.' not in out_number) or ele.isdigit():
            out_number += ele
        Elif out_number:
            break
    return float(out_number)
7
Menglong Li

特にブラジルの電話番号から文字列のマスクを削除するための解決策を探していました。この投稿は回答されていませんが、私を刺激しました。これが私の解決策です:

>>> phone_number = '+55(11)8715-9877'
>>> ''.join([n for n in phone_number if n.isdigit()])
'551187159877'
6
Sidon

これを達成するための代替手段として itertools.groupby の使用法をまだ誰も言及していないことに驚いています。

itertools.groupby()str.isdigit() と共に使用して、文字列から数字を抽出することができます。

from itertools import groupby
my_str = "hello 12 hi 89"

l = [int(''.join(i)) for is_digit, i in groupby(my_str, str.isdigit) if is_digit]

lが保持する値は次のようになります。

[12, 89]

PS:これは単なる例として、これを実現するためにgroupbyを使用することもできることを示すためのものです。ただし、これは推奨される解決策ではありません。これを実現するには、 受け入れられたfmarkの答え をフィルタとしてstr.isdigitを使ったリスト内包表記の使用に基づくべきです。

5

下記の正規表現を使用するのが方法です

lines = "hello 12 hi 89"
import re
output = []
line = lines.split()
for Word in line:
        match = re.search(r'\d+.?\d*', Word)
        if match:
            output.append(float(match.group()))
print (output)
3
user1464878

例外処理を使用して誰も追加していないため、またこれはフロートに対しても機能するため、この回答を追加しています。

a = []
line = "abcd 1234 efgh 56.78 ij"
for Word in line.split():
    try:
        a.append(float(Word))
    except ValueError:
        pass
print(a)

出力:

[1234.0, 56.78]
2
Raghav

これらのどれもが私が見つける必要があったExcelとWordの文書の現実世界の財務数値を扱っていなかったので、ここに私の変化があります。整数、浮動小数点数、負の数、通貨数を処理し(分割しても返信しないため)、小数部を削除して整数を返すか、すべてを返すかを選択できます。

また、カンマが不規則に表示される3桁ごとの間隔ではなく、Indian Laksの番号体系も処理されます。

科学的な表記法や予算内の括弧内の負の数は扱いません - 正のように見えます。

日付も抽出されません。文字列で日付を見つけるためのより良い方法があります。

import re
def find_numbers(string, ints=True):            
    numexp = re.compile(r'[-]?\d[\d,]*[\.]?[\d{2}]*') #optional - in front
    numbers = numexp.findall(string)    
    numbers = [x.replace(',','') for x in numbers]
    if ints is True:
        return [int(x.replace(',','').split('.')[0]) for x in numbers]            
    else:
        return numbers
2
Marc Maxmeister

@ jmnas、私はあなたの答えが好きでした、しかしそれはフロートを見つけませんでした。私は、CNC工場に送られるコードを解析するスクリプトを作成していますが、整数または浮動小数点数の可能性があるXとYの両方の次元を見つける必要がありました。これはintを見つけ、正と負の値でfloatを返します。それでも16進数形式の値は見つかりませんが、 "x"と "A"から "F"をnum_charタプルに追加することができ、 '0x23AC'のようなものを解析できると思います。

s = 'hello X42 I\'m a Y-32.35 string Z30'
xy = ("X", "Y")
num_char = (".", "+", "-")

l = []

tokens = s.split()
for token in tokens:

    if token.startswith(xy):
        num = ""
        for char in token:
            # print(char)
            if char.isdigit() or (char in num_char):
                num = num + char

        try:
            l.append(float(num))
        except ValueError:
            pass

print(l)
1
ZacSketches

私が見つけた最良の選択肢は以下の通りです。それは数を抽出し、どんな種類の文字も削除することができます。

def extract_nbr(input_str):
    if input_str is None or input_str == '':
        return 0

    out_number = ''
    for ele in input_str:
        if ele.isdigit():
            out_number += ele
    return float(out_number)    
0
Ajay Kumar