Разделение строки, в которой она переключается между числовыми и буквенными символами

Я разбираю некоторые данные, где стандартный формат - это что-то вроде 10 pizzas. Иногда данные вводятся правильно, и мы можем в итоге 5pizzas вместо 5 pizzas. В этом случае я хочу проанализировать количество пицц.

Наивный способ сделать это состоял бы в том, чтобы проверить символ по символу, создав строку до тех пор, пока мы не достигнем цифры, а затем произведем ее как целое число.

num_pizzas = ""
for character in data_input:
   if character.isdigit():
      num_pizzas += character
   else:
      break
num_pizzas = int(num_pizzas)

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

Ответ 1

Вы запрашиваете способ разделить строку на цифры, но тогда в вашем примере то, что вы на самом деле хотите, это просто первые числа, это легко сделать с помощью itertools.takewhile():

>>> int("".join(itertools.takewhile(str.isdigit, "10pizzas")))
10

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

Если вам нужны и более поздние данные, то то, что вы ищете, itertools.groupby() смешивается с простым список:

>>> ["".join(x) for _, x in itertools.groupby("dfsd98sd8f68as7df56", key=str.isdigit)]
['dfsd', '98', 'sd', '8', 'f', '68', 'as', '7', 'df', '56']

Если вы хотите сделать одно гигантское число:

>>> int("".join("".join(x) for is_number, x in itertools.groupby("dfsd98sd8f68as7df56", key=str.isdigit) if is_number is True))
98868756

Ответ 2

Чтобы разбить строку на цифры, вы можете использовать re.split с регулярным выражением \d+:

>>> import re
>>> def my_split(s):
    return filter(None, re.split(r'(\d+)', s))

>>> my_split('5pizzas')
['5', 'pizzas']
>>> my_split('foo123bar')
['foo', '123', 'bar']

Чтобы найти первое число, используйте re.search:

>>> re.search('\d+', '5pizzas').group()
'5'
>>> re.search('\d+', 'foo123bar').group()
'123'

Если вы знаете, что номер должен быть в начале строки, вы можете использовать re.match вместо re.search. Если вы хотите найти все цифры и отказаться от остальных, вы можете использовать re.findall.

Ответ 3

Как насчет регулярного выражения?

reg = re.compile(r'(?P<numbers>\d*)(?P<rest>.*)')
result = reg.search(str)
if result:
    numbers = result.group('numbers')
    rest = result.group('rest')