Dividindo uma string onde ela alterna entre caracteres numéricos e alfabéticos

Estou analisando alguns dados em que o formato padrão é algo como 10 pizzas . Às vezes, os dados são inseridos corretamente e podemos acabar com 5pizzas vez de 5 pizzas . Nesse cenário, quero analisar o número de pizzas.

A maneira ingênua de fazer isso seria verificar caractere por caractere, construir uma string até chegarmos a um não-dígito e, em seguida, converter essa string como um inteiro.

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

Isso é muito desajeitado, no entanto. Existe uma maneira mais fácil de dividir uma string onde ela muda de dígitos numéricos para caracteres alfabéticos?

Você pede uma maneira de dividir uma string em dígitos, mas, em seu exemplo, o que você realmente quer é apenas os primeiros números, isso é feito facilmente com itertools.takewhile() :

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

Isso faz muito sentido – o que estamos fazendo é pegar o caractere da string enquanto eles são dígitos. Isso tem a vantagem de interromper o processamento assim que chegamos ao primeiro caractere não-dígito.

Se você precisar dos dados posteriores também, então o que você está procurando é itertools.groupby() misturado com uma simples compreensão de lista :

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

Se você quiser fazer um número gigante:

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

Para dividir a string em dígitos, você pode usar re.split com a expressão regular \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'] 

Para encontrar o primeiro número use re.search :

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

Se você sabe que o número deve estar no início da string, então você pode usar re.match vez de re.search . Se você quiser encontrar todos os números e descartar o resto, você pode usar re.findall .

Como sobre um regex?

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

Resposta adicionada como forma possível de resolver Como dividir uma string em uma lista por dígitos? que foi dupe-linked a esta questão.

Você pode fazer a divisão você mesmo:

  • usar uma lista temporária para acumular caracteres que não são dígitos
  • Se você encontrar um dígito, adicione a lista temporária ( ''.join() -ed) à lista de resultados (somente se não estiver vazia) e não se esqueça de limpar a lista temporária.
  • repita até que todos os caracteres sejam processados ​​e, se as listas temporais ainda tiverem conteúdo, adicione-o

 text = "Ka12Tu12La" splitted = [] # our result tmp = [] # our temporary character collector for c in text: if not c.isdigit(): tmp.append(c) # not a digit, add it elif tmp: # c is a digit, if tmp filled, add it splitted.append(''.join(tmp)) tmp = [] if tmp: splitted.append(''.join(tmp)) print(splitted) 

Saída:

 ['Ka', 'Tu', 'La'] 

Referências:

  • O que exatamente o método .join () faz?