파이썬에서 문자열에서 숫자를 추출하는 방법은 무엇입니까?


432

문자열에 포함 된 모든 숫자를 추출합니다. 목적, 정규식 또는 isdigit()방법에 더 적합한 것은 무엇입니까?

예:

line = "hello 12 hi 89"

결과:

[12, 89]

답변:


485

양의 정수만 추출하려면 다음을 시도하십시오.

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

나는 이것이 세 가지 이유로 정규식 예제보다 낫다고 주장합니다. 먼저 다른 모듈이 필요하지 않습니다. 둘째, 정규식 미니 언어를 구문 분석 할 필요가 없기 때문에 더 읽기 쉽습니다. 셋째, 더 빠릅니다 (따라서 더 많은 파이썬) :

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 진 형식의 정수는 인식하지 않습니다. 당신이 이러한 제한을 받아 들일 수 없다면, 아래의 슬림의 대답 이 트릭을 할 것입니다.


5
이것은 "h3110 23 고양이 444.4 토끼 11-2 개"와 같은 경우에 실패합니다
sharafjaffri

8
규범적인 경우는을 사용하고 re있습니다. 그것은 일반적이고 강력한 도구입니다 (따라서 매우 유용한 것을 배우십시오). 속도는 로그 파싱에서 다소 관련이 없으며 (결국 집중적 인 수치 솔버는 아닙니다) re모듈은 표준 Python 라이브러리에 있으며로드하는 데 상처를주지 않습니다.
Ioannis Filippidis

19
나는 mumblejumble45mumblejumble하나의 숫자 만 있음을 알았던 문자열을 가지고있었습니다 . 해결책은 간단 int(filter(str.isdigit, your_string))합니다.
Jonas Lindeløv

1
사소한 의견 : 변수 str를 정의하면 str기본 파이썬에서 객체와 메소드 를 재정의합니다 . 나중에 스크립트에서 필요할 수 있기 때문에 좋은 습관이 아닙니다.
Jonas Lindeløv

11
int(filter(...))올릴 것이다 TypeError: int() argument must be a string...: 당신이 업데이트 된 버전을 사용할 수 있도록, 파이썬 3.5 int(''.join(filter(str.isdigit, your_string)))하나 개의 정수로 모든 숫자를 추출.
Mark Mishyn

449

정규 표현식을 사용합니다.

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

또한의 42와 일치 bla42bla합니다. 단어 경계 (공백, 마침표, 쉼표)로 구분 된 숫자 만 원하는 경우 \ 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]

9
... 그리고 그 int위에 매핑 하면 완료됩니다. 후자의 경우 특히 +1. 그래도 원시 문자열 ( r'\b\d+\b' == '\\b\\d+\\b')을 제안 합니다.

5
다음과 같은 생성기를 사용하여 목록에 넣을 수 있습니다.int_list = [int(s) for s in re.findall('\\d+', 'hello 12 hi 89')]
GreenMatt

7
@ GreenMatt : 기술적으로 목록 이해 (생성자가 아님)이지만 이해력 / 생성자는 파이썬보다 더 동의한다는 데 동의합니다 map.
세스 존슨

1
@Seth Johnson : 죄송합니다! 네 말이 맞아, 나는 안개가 자욱한 마음의 상태로 잘못 입력했다. :-( 수정 주셔서 감사합니다!
GreenMatt

2
그래도 문제가 있습니다. "hello1.45 hi"에서 1.45와 같은 플로트 숫자를 추출하려면 어떻게해야합니까? 그것은 두 개의 서로 다른 숫자로 나에게 (1) 및 (45)을 줄 것이다
AB123

89

이것은 조금 늦었지만 과학적 표기법을 설명하기 위해 정규 표현식을 확장 할 수 있습니다.

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 내장 정규식을 볼 수 있습니다


1
이 답변은 누구나 좋아하는 유일한 답변이므로 과학 표기법 "[-+]? \ d + [\.]? \ d * [Ee]? \ d *"를 사용하여 수행하는 방법은 다음과 같습니다. 또는 약간의 변형. 즐기세요!
aidan.plenert.macdonald

가장 간단한 경우에 문제가 있음을 찾으십시오 s = "4". 예를 들어 일치 항목이 없습니다. 이 문제를 해결하기 위해 다시 편집 할 수 있습니까?
batFINGER

1
훌륭하지만 쉼표를 처리하지 않습니다 (예 :
74,600

더 자세한 그룹은 [+-]?\d*[\.]?\d*(?:(?:[eE])[+-]?\d+)?이 그룹은 잘못된 긍정 (예 : +때때로 자체적으로 캡처 됨 )을 제공 .001s=2+1
하지만와

24
아, 그렇습니다. [-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?나의 어리석은 일 ... 어떻게 생각할 수 없습니까?
Przemek D

70

정수가 아닌 부동 소수점을 원한다고 가정하므로 다음과 같이하십시오.

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

이것은 양수 및 음수 부동 소수점과 정수를 찾습니다. 양수와 음수의 정수만으로 변경 float하십시오 int.
Hugo

3
음수의 경우 :re.findall("[-\d]+", "1 -2")
ytpillai

루프 continue대신에 쓰면 어떤 차이가 pass있습니까?
D. Jones

이 캐치 더 다만 양의 정수보다 더 있지만, 재무 문서에 공통없는 공간으로 첫 번째 숫자 앞에 통화 기호가 번호를 그리워 할 것이다 분할 ()를 사용하여
마크 Maxmeister

다른 문자와 함께 공백이없는 플로트에는 작동하지 않습니다. 예 : '4.5k 일'이 작동하고 '4.5k 일'이 작동하지 않습니다.
Jay D.

64

문자열에서 하나의 숫자 만 알고 있다면 (예 : 'hello 12 hi') 필터를 사용해 볼 수 있습니다.

예를 들면 다음과 같습니다.

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

12
Python 3.6.3에서는 TypeError: int() argument must be a string, a bytes-like object or a number, not 'filter'다음을 사용하여 수정했습니다.int("".join(filter(str.isdigit, '200 grams')))
Kent Munthe Caspersen

16
# extract numbers from garbage string:
s = '12//n,_@#$%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]

3
SO에 오신 것을 환영합니다. 답변을 게시 해 주셔서 감사합니다. 코드 스 니펫을 게시하는 대신 답변에 의견을 추가하고 문제를 해결하는 이유를 항상 추가하는 것이 좋습니다.
sebs

내 경우에는 작동하지 않았다. 위의 답변과 크게 다르지 않습니다
oldboy

ValueError : 문자열을 float로 변환 할 수 없습니다 : 'e'그리고 어떤 경우에는 작동하지 않습니다 :(
Vilq

15

브라질 전화 번호에서 문자열 마스크를 제거하는 솔루션을 찾고 있었는데이 게시물은 대답하지 않았지만 영감을 얻었습니다. 이것은 내 솔루션입니다.

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

12

아래 정규식을 사용하는 방법입니다

lines = "hello 12 hi 89"
import re
output = []
#repl_str = re.compile('\d+.?\d*')
repl_str = re.compile('^\d+$')
#t = r'\d+.?\d*'
line = lines.split()
for word in line:
        match = re.search(repl_str, word)
        if match:
            output.append(float(match.group()))
print (output)

findall과 함께 re.findall(r'\d+', "hello 12 hi 89")

['12', '89']

re.findall(r'\b\d+\b', "hello 12 hi 89 33F AC 777")

 ['12', '89', '777']

사용하지 않는 경우 최소한 정규식을 컴파일해야합니다.findall()
information_interchange

2
repl_str = re.compile('\d+.?\d*') 같아야 repl_str = re.compile('\d+\.?\d*') 재생 가능한 예를 들어 사용 python3.7 re.search(re.compile(r'\d+.?\d*'), "42G").group() '42G' re.search(re.compile(r'\d+\.?\d*'), "42G").group() 42 ''
알렉시스 Lucattini

8
line2 = "hello 12 hi 89"
temp1 = re.findall(r'\d+', line2) # through regular expression
res2 = list(map(int, temp1))
print(res2)

안녕 ,

findall expression을 사용하여 숫자를 통해 문자열의 모든 정수를 검색 할 수 있습니다.

두 번째 단계에서 res2 목록을 작성하고 문자열에서 찾은 숫자를이 목록에 추가하십시오.

도움이 되었기를 바랍니다

감사합니다. Diwakar Sharma


제공된 답변은 검토를 위해 저품질 게시물로 표시되었습니다. 다음은 좋은 답변을 작성하는 방법에 대한 몇 가지 지침입니다 . . 이 답변은 정확할 수도 있지만 설명이 도움이 될 수 있습니다. 코드 전용 답변은 "좋은"답변으로 간주되지 않습니다. 에서 검토 .
Trenton McKinney

간단하고 효과적인 솔루션
moyo

7

이 답변에는 숫자가 문자열에 떠있는 경우도 포함됩니다.

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)

5

아무도 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]

추신 : 이것은 단지 대안으로 우리가 groupby이것을 달성 하는 데 사용할 수 있음을 보여주기위한 설명 을위한 것입니다. 그러나 이것은 권장되는 솔루션이 아닙니다. 이를 달성하려면 목록 이해를 필터 로 사용하여 허용 된 fmark 응답을 사용해야str.isdigit 합니다.


4

아무도 예외 처리를 사용하여 아무도 추가하지 않았기 때문에이 답변을 추가하고 있습니다.

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]

3

다른 패턴을 잡으려면 다른 패턴으로 쿼리하는 것이 좋습니다.

관심있는 다른 숫자 패턴을 잡는 모든 패턴을 설정하십시오.

(쉼표를 찾습니다) 12,300 또는 12,300.00

'[\ d] + [., \ d] +'

(수레를 찾습니다) 0.123 또는 .123

'[\ d] * [.] [\ d] +'

(정수를 찾습니다) 123

'[\ d] +'

파이프 (|)를 여러 개 또는 조건부 로 하나의 패턴으로 결합하십시오 .

(참고 : 복잡한 패턴을 먼저 넣으면 간단한 패턴이 전체 캐치를 반환하는 복잡한 캐치 대신 복잡한 캐치 덩어리를 반환합니다).

p = '[\d]+[.,\d]+|[\d]*[.][\d]+|[\d]+'

아래에가있는 패턴이 있는지 확인한 re.search()다음 반복 가능한 캐치 목록을 반환합니다. 마지막으로 대괄호 표기법을 사용하여 각 캐치를 인쇄하여 일치 개체에서 일치 개체 반환 값을 하위 선택합니다.

s = 'he33llo 42 I\'m a 32 string 30 444.4 12,001'

if re.search(p, s) is not None:
    for catch in re.finditer(p, s):
        print(catch[0]) # catch is a match object

보고:

33
42
32
30
444.4
12,001

2

이 중 어느 것도 내가 찾아야 할 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

1

@ jmnas, 나는 당신의 대답을 좋아했지만 수레를 찾지 못했습니다. CNC 밀로가는 코드를 구문 분석하는 스크립트를 작성 중이며 정수 또는 부동 소수점 일 수있는 X 및 Y 차원을 모두 찾아야하므로 코드를 다음과 같이 조정했습니다. 이것은 int를 찾고 양수와 음수로 플로트합니다. 여전히 16 진수 형식의 값을 찾지 못하지만 "F"를 통해 "x"와 "A"를 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)

0

내가 찾은 가장 좋은 옵션은 다음과 같습니다. 숫자를 추출하여 모든 유형의 문자를 제거 할 수 있습니다.

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

전화 번호의 경우 정규식에서 \ D로 숫자가 아닌 모든 문자를 제외시킬 수 있습니다.

import re

phone_number = '(619) 459-3635'
phone_number = re.sub(r"\D", "", phone_number)
print(phone_number)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.