it-swarm.com.ru

Как извлечь числа из строки в Python?

Я бы извлек все числа, содержащиеся в строке. Что лучше подходит для этой цели, регулярных выражений или метода isdigit()?

Пример:

line = "hello 12 hi 89"

Результат:

[12, 89]
349
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

Это не будет распознавать числа с плавающей запятой, отрицательные целые числа или целые числа в шестнадцатеричном формате. Если вы не можете принять эти ограничения, ответ Слима ниже добьется цели.

397
fmark

Я бы использовал регулярное выражение:

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

Это также будет соответствовать 42 из bla42bla. Если вам нужны только числа, разделенные границами Word (пробел, точка, запятая), вы можете использовать\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]
371
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

77
aidan.plenert.macdonald

Я предполагаю, что вы хотите, чтобы числа с плавающей точкой не просто целые числа, поэтому я бы сделал что-то вроде этого:

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

Если вы знаете, что в строке будет только одно число, то есть "привет 12 привет", вы можете попробовать фильтр.

Например:

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
50
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]
11
AndreiS

Этот ответ также содержит случай, когда число находится в строке

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

Использование Regex ниже - это способ

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)
5
user1464878

Я поражен, увидев, что еще никто не упомянул об использовании 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
Moinuddin Quadri

Я просто добавляю этот ответ, потому что никто не добавил один, использующий обработку исключений, и потому что это также работает для чисел с плавающей запятой.

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 числа.

Он не обрабатывает научные обозначения или отрицательные числа, заключенные в круглые скобки в бюджетах - будет казаться положительным.

Это также не извлекает даты. Есть лучшие способы поиска дат в строках.

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, мне понравился твой ответ, но он не нашел поплавков. Я работаю над сценарием для анализа кода, идущего на станки с ЧПУ, и мне нужно было найти измерения X и Y, которые могут быть целыми или плавающими, поэтому я адаптировал ваш код к следующему. Это находит int, float с положительными и отрицательными значениями. Все еще не находит значения в шестнадцатеричном формате, но вы можете добавить "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