Expressão regular para combinar números com ou sem vírgulas e decimais no texto

97

Estou tentando localizar e substituir todos os números em um corpo de texto. Encontrei alguns exemplos de regex, que quase resolvem o problema, mas nenhum é perfeito ainda. O problema que tenho é que os números no meu texto podem ou não ter decimais e vírgulas. Por exemplo:

"A raposa de 5.000 libras pulou uma cerca de 99.999.99998713 pés."

O regex deve retornar " 5000" e " 99,999.99998713". Exemplos que encontrei separando os números na vírgula ou estão limitados a duas casas decimais. Estou começando a entender o regex o suficiente para ver por que alguns exemplos são limitados a duas casas decimais, mas ainda não aprendi como superá-lo e também incluir a vírgula para obter a sequência inteira.

Aqui está minha última versão:

[0-9]+(\.[0-9][0-9]?)?

Que retorna, " 5000", " 99,99", " 9.99" e " 998713" para o texto acima.

Rosquinha
fonte
1
Que tipo de linguagem de programação ou regex?
Matt Ball
7
Parece que quase todas as respostas aqui cometem o erro de permitir coisas como .,.,.ou 9,9,9,9ou 9,9.99.9. Essas regexes não exigem que os números estejam no formato adequado e, na pior das hipóteses, tratam a pontuação como números. Existem alguns ajustes opcionais possíveis (por exemplo, se permitir zeros à esquerda e à direita), mas algumas das respostas que estou vendo estão totalmente incorretas. Eu realmente não gosto de downvoting, especialmente em tentativas honestas, mas sinto que as respostas aqui precisam ser limpas. Esta é uma pergunta comum e com certeza será feita novamente.
Justin Morgan
Caso você não o conheça, dê uma olhada em regexpal.com
entonio
Desculpe pela demora, Matt. Estou usando o ActionScript 3. da Adobe. Achei que o comportamento do regex era o mesmo do JavaScript, mas testei a sugestão de Justin em regexpal.com e comparei com os resultados do meu aplicativo Flash e vi dois resultados diferentes, ambos errados.
Deve funcionar desta vez, com base em meus próprios testes. Deixe-me saber se ainda precisa de aprimoramento.
Justin Morgan

Respostas:

289

EDIT: Como isso gerou muitas visualizações, deixe-me começar dando a todos o que eles procuraram no Google:

#ALL THESE REQUIRE THE WHOLE STRING TO BE A NUMBER
#For numbers embedded in sentences, see discussion below

#### NUMBERS AND DECIMALS ONLY ####
#No commas allowed
#Pass: (1000.0), (001), (.001)
#Fail: (1,000.0)
^\d*\.?\d+$

#No commas allowed
#Can't start with "."
#Pass: (0.01)
#Fail: (.01)
^(\d+\.)?\d+$

#### CURRENCY ####
#No commas allowed
#"$" optional
#Can't start with "."
#Either 0 or 2 decimal digits
#Pass: ($1000), (1.00), ($0.11)
#Fail: ($1.0), (1.), ($1.000), ($.11)
^\$?\d+(\.\d{2})?$

#### COMMA-GROUPED ####
#Commas required between powers of 1,000
#Can't start with "."
#Pass: (1,000,000), (0.001)
#Fail: (1000000), (1,00,00,00), (.001)
^\d{1,3}(,\d{3})*(\.\d+)?$

#Commas required
#Cannot be empty
#Pass: (1,000.100), (.001)
#Fail: (1000), ()
^(?=.)(\d{1,3}(,\d{3})*)?(\.\d+)?$

#Commas optional as long as they're consistent
#Can't start with "."
#Pass: (1,000,000), (1000000)
#Fail: (10000,000), (1,00,00)
^(\d+|\d{1,3}(,\d{3})*)(\.\d+)?$

#### LEADING AND TRAILING ZEROES ####
#No commas allowed
#Can't start with "."
#No leading zeroes in integer part
#Pass: (1.00), (0.00)
#Fail: (001)
^([1-9]\d*|0)(\.\d+)?$

#No commas allowed
#Can't start with "."
#No trailing zeroes in decimal part
#Pass: (1), (0.1)
#Fail: (1.00), (0.1000)
^\d+(\.\d*[1-9])?$

Agora que isso já foi resolvido, a maior parte do que se segue é um comentário sobre como a regex complexa pode ficar se você tentar ser inteligente com ela e por que deve buscar alternativas. Leia por sua própria conta e risco.


Esta é uma tarefa muito comum, mas todas as respostas que eu vejo aqui até agora aceitará entradas que não correspondem a sua formatação de números, tais como ,111, 9,9,9ou mesmo .,,.. Isso é bastante simples de corrigir, mesmo se os números estiverem incorporados em outro texto. IMHO qualquer coisa que não consegue puxar 1,234.56 e 1234- e somente aqueles números out of abc22 1,234.56 9.9.9.9 def 1234é uma resposta errada.

Em primeiro lugar, se você não precisa fazer tudo em uma regex, não faça. É difícil manter uma única regex para dois formatos de número diferentes, mesmo quando eles não estão incorporados em outro texto. O que você realmente deve fazer é dividir tudo em espaços em branco e, em seguida, executar duas ou três expressões regulares menores nos resultados. Se essa não for uma opção para você, continue lendo.

Padrão básico

Considerando os exemplos que você deu, aqui está um regex simples que permite praticamente qualquer número inteiro ou decimal no 0000formato e bloqueia todo o resto:

^\d*\.?\d+$

Aqui está um que requer 0,000formato:

^\d{1,3}(,\d{3})*(\.\d+)?$

Coloque-os juntos e as vírgulas se tornam opcionais, desde que sejam consistentes:

^(\d*\.?\d+|\d{1,3}(,\d{3})*(\.\d+)?)$

Números embutidos

Os padrões acima requerem que toda a entrada seja um número. Você está procurando por números embutidos no texto, então você tem que afrouxar essa parte. Por outro lado, você não quer que ele veja catch22e pense que encontrou o número 22. Se você estiver usando algo com suporte para lookbehind (como .NET), isso é muito fácil: substitua ^por (?<!\S)e $por (?!\S)e você estará bem ir:

(?<!\S)(\d*\.?\d+|\d{1,3}(,\d{3})*(\.\d+)?)(?!\S)

Se você está trabalhando com JavaScript ou Ruby ou algo assim, as coisas começam a parecer mais complexas:

(?:^|\s)(\d*\.?\d+|\d{1,3}(?:,\d{3})*(?:\.\d+)?)(?!\S)

Você terá que usar grupos de captura; Não consigo pensar em uma alternativa sem o apoio de olhar para trás. Os números que você deseja estarão no Grupo 1 (assumindo que a partida inteira seja o Grupo 0).

Validação e regras mais complexas

Acho que isso cobre sua pergunta, então se isso é tudo de que você precisa, pare de ler agora. Se você quiser ficar mais sofisticado, as coisas se tornam muito complexas muito rapidamente. Dependendo da sua situação, você pode bloquear um ou todos os seguintes:

  • Entrada vazia
  • Zeros à esquerda (por exemplo, 000123)
  • Zeros à direita (por exemplo, 1.2340000)
  • Decimais começando com o ponto decimal (por exemplo, 0,001 em oposição a 0,001)

Só por diversão, vamos supor que você queira bloquear os primeiros 3, mas permitir o último. O que você deveria fazer? Vou te dizer o que você deve fazer, você deve usar uma regex diferente para cada regra e restringir progressivamente suas correspondências. Mas pelo bem do desafio, veja como você faz tudo em um padrão gigante:

(?<!\S)(?=.)(0|([1-9](\d*|\d{0,2}(,\d{3})*)))?(\.\d*[1-9])?(?!\S)

E aqui está o que significa:

(?<!\S) to (?!\S) #The whole match must be surrounded by either whitespace or line boundaries. So if you see something bogus like :;:9.:, ignore the 9.
(?=.)             #The whole thing can't be blank.

(                    #Rules for the integer part:
  0                  #1. The integer part could just be 0...
  |                  #
  [1-9]              #   ...otherwise, it can't have leading zeroes.
  (                  #
    \d*              #2. It could use no commas at all...
    |                #
    \d{0,2}(,\d{3})* #   ...or it could be comma-separated groups of 3 digits each.
  )                  # 
)?                   #3. Or there could be no integer part at all.

(       #Rules for the decimal part:
  \.    #1. It must start with a decimal point...
  \d*   #2. ...followed by a string of numeric digits only.
  [1-9] #3. It can't be just the decimal point, and it can't end in 0.
)?      #4. The whole decimal part is also optional. Remember, we checked at the beginning to make sure the whole thing wasn't blank.

Testado aqui: http://rextester.com/YPG96786

Isso permitirá coisas como:

100,000
999.999
90.0009
1,000,023.999
0.111
.111
0

Isso irá bloquear coisas como:

1,1,1.111
000,001.111
999.
0.
111.110000
1.1.1.111
9.909,888

Existem várias maneiras de tornar este regex mais simples e curto, mas entenda que alterar o padrão afrouxará o que ele considera um número.

Uma vez que muitos mecanismos de regex (por exemplo, JavaScript e Ruby) não suportam o lookbehind negativo, a única maneira de fazer isso corretamente é com grupos de captura:

(:?^|\s)(?=.)((?:0|(?:[1-9](?:\d*|\d{0,2}(?:,\d{3})*)))?(?:\.\d*[1-9])?)(?!\S)

Os números que você está procurando estarão no grupo de captura 1.

Testado aqui: http://rubular.com/r/3HCSkndzhT

Uma nota final

Obviamente, este é um regex enorme, complicado e quase ilegível. Gostei do desafio, mas você deve considerar se realmente deseja usar isso em um ambiente de produção. Em vez de tentar fazer tudo em uma etapa, você pode fazer em duas: uma regex para capturar qualquer coisa que possa ser um número, depois outra para eliminar o que não for um número. Ou você pode fazer algum processamento básico e, em seguida, usar as funções integradas de análise de números da sua linguagem. Sua escolha.

Justin Morgan
fonte
1
Esta é uma tentativa muito boa, mas pode haver um problema com ela - dependendo da ganância do motor, um determinado número pode corresponder parcialmente a dois dos formatos concorrentes, instrad de combinar individualmente o correto - ou seja, 5000 pode render 500 mais 0 Isso me deixa um pouco cético quanto a tentar cobrir muito com apenas uma única expressão, e é por isso que dei uma resposta mais simples com a ressalva de possíveis falsos positivos. No final das contas, o rigor dos requisitos deve ditar a solução.
entonio
@entonio - É um ponto justo. Pode funcionar com a edição mais recente. BTW, seu downvote não era meu, já que você apontou o potencial de 1,11,11.
Justin Morgan
Estou usando o ActionScript, que acredito se comportar da mesma forma que o JavaScript. Usando o primeiro padrão que você recomendou, obtenho os seguintes resultados em minha string de teste (para validação, estou simplesmente retornando as correspondências agrupadas em "<< [resultado] >>"): O << 5 >> 000 lb. saltou uma << 9 >> 9 <<, 9 >> <<99>> <<. 9 >> <<99>> <<98>> <<71>> cerca de 3 pés.
2
Bem, um de seus votos a favor é meu :) como eu acho que sua resposta é a mais completa possível e você se esforçou. Só para fazer disso um comentário de conteúdo, uma nota para o OP, o?: No início dos grupos existe para que eles não sejam retornados autonomamente no resultado ('capturados'), embora contribuam para a correspondência de toda a expressão; cada número formatado na entrada corresponde a toda a expressão.
entonio
@Michael e @entonio - Veja a última edição, que parece funcionar. Este é um daqueles problemas de regex que são mais difíceis do que parecem.
Justin Morgan
10

Alguns dias atrás, trabalhei no problema de remover os zeros à direita da sequência de um número .

Na continuidade desse problema, acho este interessante porque amplia o problema para números compreendendo vírgulas.

Peguei o padrão de regex que escrevi no problema anterior em que trabalhei e o melhorei para que pudesse tratar os números com vírgulas como uma resposta para esse problema.

Tenho me deixado levar pelo meu entusiasmo e pelo meu gosto por regexes. Não sei se o resultado se encaixa exatamente à necessidade expressa por Michael Prescott. Eu estaria interessado em saber os pontos que estão em excesso ou em falta na minha regex e em corrigi-la para torná-la mais adequada para você.

Agora, depois de uma longa sessão de trabalho nesta regex, tenho uma espécie de peso no cérebro, então não estou fresco o suficiente para dar muitas explicações. Se os pontos são obscuros, e se alguém pode vir a se interessar o suficiente, por favor, pergunte-me.

A regex é construída de forma que possa detectar os números expressos em notação científica 2E10 ou mesmo 5.22.454.12E-00.0478 , removendo zeros desnecessários nas duas partes de tais números também. Se um expoente for igual a zero, o número é modificado para que não haja mais expoente.

Eu coloquei alguma verificação no padrão para que alguns casos particulares não correspondam, por exemplo '12 ..57 ' não correspondessem. Mas em ', 111' a string '111' corresponde porque a vírgula anterior é considerada uma vírgula não estando em um número, mas uma vírgula de frase.

Acho que o gerenciamento de vírgulas deve ser melhorado, porque me parece que existem apenas 2 dígitos entre vírgulas na numeração indiana. Não será difícil corrigir, presumo

A seguir está um código que demonstra como meu regex funciona. Existem duas funções, conforme se quer os números '.1245' sejam transformados em '0,1245' ou não. Eu não ficaria surpreso se erros ou correspondências indesejadas ou não correspondências permanecessem para certos casos de cadeias de números; então gostaria de conhecer esses casos para entender e corrigir a deficiência.

Peço desculpas por este código escrito em Python, mas regexes são trans-idioma e acho que todos serão capazes de entender o padrão do reex

import re

regx = re.compile('(?<![\d.])(?!\.\.)(?<![\d.][eE][+-])(?<![\d.][eE])(?<!\d[.,])'
                  '' #---------------------------------
                  '([+-]?)'
                  '(?![\d,]*?\.[\d,]*?\.[\d,]*?)'
                  '(?:0|,(?=0)|(?<!\d),)*'
                  '(?:'
                  '((?:\d(?!\.[1-9])|,(?=\d))+)[.,]?'
                  '|\.(0)'
                  '|((?<!\.)\.\d+?)'
                  '|([\d,]+\.\d+?))'
                  '0*'
                  '' #---------------------------------
                  '(?:'
                  '([eE][+-]?)(?:0|,(?=0))*'
                  '(?:'
                  '(?!0+(?=\D|\Z))((?:\d(?!\.[1-9])|,(?=\d))+)[.,]?'
                  '|((?<!\.)\.(?!0+(?=\D|\Z))\d+?)'
                  '|([\d,]+\.(?!0+(?=\D|\Z))\d+?))'
                  '0*'
                  ')?'
                  '' #---------------------------------
                  '(?![.,]?\d)')


def dzs_numbs(x,regx = regx): # ds = detect and zeros-shave
    if not regx.findall(x):
        yield ('No match,', 'No catched string,', 'No groups.')
    for mat in regx.finditer(x):
        yield (mat.group(), ''.join(mat.groups('')), mat.groups(''))

def dzs_numbs2(x,regx = regx): # ds = detect and zeros-shave
    if not regx.findall(x):
        yield ('No match,', 'No catched string,', 'No groups.')
    for mat in regx.finditer(x):
        yield (mat.group(),
               ''.join(('0' if n.startswith('.') else '')+n for n in mat.groups('')),
               mat.groups(''))

NS = ['  23456000and23456000. or23456000.000  00023456000 s000023456000.  000023456000.000 ',
      'arf 10000 sea10000.+10000.000  00010000-00010000. kant00010000.000 ',
      '  24:  24,  24.   24.000  24.000,   00024r 00024. blue 00024.000  ',
      '  8zoom8.  8.000  0008  0008. and0008.000  ',
      '  0   00000M0. = 000.  0.0  0.000    000.0   000.000   .000000   .0   ',
      '  .0000023456    .0000023456000   '
      '  .0005872    .0005872000   .00503   .00503000   ',
      '  .068    .0680000   .8   .8000  .123456123456    .123456123456000    ',
      '  .657   .657000   .45    .4500000   .7    .70000  0.0000023230000   000.0000023230000   ',
      '  0.0081000    0000.0081000  0.059000   0000.059000     ',
      '  0.78987400000 snow  00000.78987400000  0.4400000   00000.4400000   ',
      '  -0.5000  -0000.5000   0.90   000.90   0.7   000.7   ',
      '  2.6    00002.6   00002.60000  4.71   0004.71    0004.7100   ',
      '  23.49   00023.49   00023.490000  103.45   0000103.45   0000103.45000    ',
      '  10003.45067   000010003.45067   000010003.4506700 ',
      '  +15000.0012   +000015000.0012   +000015000.0012000    ',
      '  78000.89   000078000.89   000078000.89000    ',
      '  .0457e10   .0457000e10   00000.0457000e10  ',
      '   258e8   2580000e4   0000000002580000e4   ',
      '  0.782e10   0000.782e10   0000.7820000e10  ',
      '  1.23E2   0001.23E2  0001.2300000E2   ',
      '  432e-102  0000432e-102   004320000e-106   ',
      '  1.46e10and0001.46e10  0001.4600000e10   ',
      '  1.077e-300  0001.077e-300  0001.077000e-300   ',
      '  1.069e10   0001.069e10   0001.069000e10   ',
      '  105040.03e10  000105040.03e10  105040.0300e10    ',
      '  +286E000024.487900  -78.4500e.14500   .0140E789.  ',
      '  081,12.40E07,95.0120     0045,78,123.03500e-0.00  ',
      '  0096,78,473.0380e-0.    0008,78,373.066000E0.    0004512300.E0000  ',
      '  ..18000  25..00 36...77   2..8  ',
      '  3.8..9    .12500.     12.51.400  ',
      '  00099,111.8713000   -0012,45,83,987.26+0.000,099,88,44.or00,00,00.00must',
      '  00099,44,and   0000,099,88,44.bom',
      '00,000,00.587000  77,98,23,45.,  this,that ',
      '  ,111  145.20  +9,9,9  0012800  .,,.  1  100,000 ',
      '1,1,1.111  000,001.111   -999.  0.  111.110000  1.1.1.111  9.909,888']


for ch in NS:
    print 'string: '+repr(ch)
    for strmatch, modified, the_groups in dzs_numbs2(ch):
        print strmatch.rjust(20),'',modified,'',the_groups
    print

resultado

string: '  23456000and23456000. or23456000.000  00023456000 s000023456000.  000023456000.000 '
            23456000  23456000  ('', '23456000', '', '', '', '', '', '', '')
           23456000.  23456000  ('', '23456000', '', '', '', '', '', '', '')
        23456000.000  23456000  ('', '23456000', '', '', '', '', '', '', '')
         00023456000  23456000  ('', '23456000', '', '', '', '', '', '', '')
       000023456000.  23456000  ('', '23456000', '', '', '', '', '', '', '')
    000023456000.000  23456000  ('', '23456000', '', '', '', '', '', '', '')

string: 'arf 10000 sea10000.+10000.000  00010000-00010000. kant00010000.000 '
               10000  10000  ('', '10000', '', '', '', '', '', '', '')
              10000.  10000  ('', '10000', '', '', '', '', '', '', '')
           10000.000  10000  ('', '10000', '', '', '', '', '', '', '')
            00010000  10000  ('', '10000', '', '', '', '', '', '', '')
           00010000.  10000  ('', '10000', '', '', '', '', '', '', '')
        00010000.000  10000  ('', '10000', '', '', '', '', '', '', '')

string: '  24:  24,  24.   24.000  24.000,   00024r 00024. blue 00024.000  '
                  24  24  ('', '24', '', '', '', '', '', '', '')
                 24,  24  ('', '24', '', '', '', '', '', '', '')
                 24.  24  ('', '24', '', '', '', '', '', '', '')
              24.000  24  ('', '24', '', '', '', '', '', '', '')
              24.000  24  ('', '24', '', '', '', '', '', '', '')
               00024  24  ('', '24', '', '', '', '', '', '', '')
              00024.  24  ('', '24', '', '', '', '', '', '', '')
           00024.000  24  ('', '24', '', '', '', '', '', '', '')

string: '  8zoom8.  8.000  0008  0008. and0008.000  '
                   8  8  ('', '8', '', '', '', '', '', '', '')
                  8.  8  ('', '8', '', '', '', '', '', '', '')
               8.000  8  ('', '8', '', '', '', '', '', '', '')
                0008  8  ('', '8', '', '', '', '', '', '', '')
               0008.  8  ('', '8', '', '', '', '', '', '', '')
            0008.000  8  ('', '8', '', '', '', '', '', '', '')

string: '  0   00000M0. = 000.  0.0  0.000    000.0   000.000   .000000   .0   '
                   0  0  ('', '0', '', '', '', '', '', '', '')
               00000  0  ('', '0', '', '', '', '', '', '', '')
                  0.  0  ('', '0', '', '', '', '', '', '', '')
                000.  0  ('', '0', '', '', '', '', '', '', '')
                 0.0  0  ('', '', '0', '', '', '', '', '', '')
               0.000  0  ('', '', '0', '', '', '', '', '', '')
               000.0  0  ('', '', '0', '', '', '', '', '', '')
             000.000  0  ('', '', '0', '', '', '', '', '', '')
             .000000  0  ('', '', '0', '', '', '', '', '', '')
                  .0  0  ('', '', '0', '', '', '', '', '', '')

string: '  .0000023456    .0000023456000     .0005872    .0005872000   .00503   .00503000   '
         .0000023456  0.0000023456  ('', '', '', '.0000023456', '', '', '', '', '')
      .0000023456000  0.0000023456  ('', '', '', '.0000023456', '', '', '', '', '')
            .0005872  0.0005872  ('', '', '', '.0005872', '', '', '', '', '')
         .0005872000  0.0005872  ('', '', '', '.0005872', '', '', '', '', '')
              .00503  0.00503  ('', '', '', '.00503', '', '', '', '', '')
           .00503000  0.00503  ('', '', '', '.00503', '', '', '', '', '')

string: '  .068    .0680000   .8   .8000  .123456123456    .123456123456000    '
                .068  0.068  ('', '', '', '.068', '', '', '', '', '')
            .0680000  0.068  ('', '', '', '.068', '', '', '', '', '')
                  .8  0.8  ('', '', '', '.8', '', '', '', '', '')
               .8000  0.8  ('', '', '', '.8', '', '', '', '', '')
       .123456123456  0.123456123456  ('', '', '', '.123456123456', '', '', '', '', '')
    .123456123456000  0.123456123456  ('', '', '', '.123456123456', '', '', '', '', '')

string: '  .657   .657000   .45    .4500000   .7    .70000  0.0000023230000   000.0000023230000   '
                .657  0.657  ('', '', '', '.657', '', '', '', '', '')
             .657000  0.657  ('', '', '', '.657', '', '', '', '', '')
                 .45  0.45  ('', '', '', '.45', '', '', '', '', '')
            .4500000  0.45  ('', '', '', '.45', '', '', '', '', '')
                  .7  0.7  ('', '', '', '.7', '', '', '', '', '')
              .70000  0.7  ('', '', '', '.7', '', '', '', '', '')
     0.0000023230000  0.000002323  ('', '', '', '.000002323', '', '', '', '', '')
   000.0000023230000  0.000002323  ('', '', '', '.000002323', '', '', '', '', '')

string: '  0.0081000    0000.0081000  0.059000   0000.059000     '
           0.0081000  0.0081  ('', '', '', '.0081', '', '', '', '', '')
        0000.0081000  0.0081  ('', '', '', '.0081', '', '', '', '', '')
            0.059000  0.059  ('', '', '', '.059', '', '', '', '', '')
         0000.059000  0.059  ('', '', '', '.059', '', '', '', '', '')

string: '  0.78987400000 snow  00000.78987400000  0.4400000   00000.4400000   '
       0.78987400000  0.789874  ('', '', '', '.789874', '', '', '', '', '')
   00000.78987400000  0.789874  ('', '', '', '.789874', '', '', '', '', '')
           0.4400000  0.44  ('', '', '', '.44', '', '', '', '', '')
       00000.4400000  0.44  ('', '', '', '.44', '', '', '', '', '')

string: '  -0.5000  -0000.5000   0.90   000.90   0.7   000.7   '
             -0.5000  -0.5  ('-', '', '', '.5', '', '', '', '', '')
          -0000.5000  -0.5  ('-', '', '', '.5', '', '', '', '', '')
                0.90  0.9  ('', '', '', '.9', '', '', '', '', '')
              000.90  0.9  ('', '', '', '.9', '', '', '', '', '')
                 0.7  0.7  ('', '', '', '.7', '', '', '', '', '')
               000.7  0.7  ('', '', '', '.7', '', '', '', '', '')

string: '  2.6    00002.6   00002.60000  4.71   0004.71    0004.7100   '
                 2.6  2.6  ('', '', '', '', '2.6', '', '', '', '')
             00002.6  2.6  ('', '', '', '', '2.6', '', '', '', '')
         00002.60000  2.6  ('', '', '', '', '2.6', '', '', '', '')
                4.71  4.71  ('', '', '', '', '4.71', '', '', '', '')
             0004.71  4.71  ('', '', '', '', '4.71', '', '', '', '')
           0004.7100  4.71  ('', '', '', '', '4.71', '', '', '', '')

string: '  23.49   00023.49   00023.490000  103.45   0000103.45   0000103.45000    '
               23.49  23.49  ('', '', '', '', '23.49', '', '', '', '')
            00023.49  23.49  ('', '', '', '', '23.49', '', '', '', '')
        00023.490000  23.49  ('', '', '', '', '23.49', '', '', '', '')
              103.45  103.45  ('', '', '', '', '103.45', '', '', '', '')
          0000103.45  103.45  ('', '', '', '', '103.45', '', '', '', '')
       0000103.45000  103.45  ('', '', '', '', '103.45', '', '', '', '')

string: '  10003.45067   000010003.45067   000010003.4506700 '
         10003.45067  10003.45067  ('', '', '', '', '10003.45067', '', '', '', '')
     000010003.45067  10003.45067  ('', '', '', '', '10003.45067', '', '', '', '')
   000010003.4506700  10003.45067  ('', '', '', '', '10003.45067', '', '', '', '')

string: '  +15000.0012   +000015000.0012   +000015000.0012000    '
         +15000.0012  +15000.0012  ('+', '', '', '', '15000.0012', '', '', '', '')
     +000015000.0012  +15000.0012  ('+', '', '', '', '15000.0012', '', '', '', '')
  +000015000.0012000  +15000.0012  ('+', '', '', '', '15000.0012', '', '', '', '')

string: '  78000.89   000078000.89   000078000.89000    '
            78000.89  78000.89  ('', '', '', '', '78000.89', '', '', '', '')
        000078000.89  78000.89  ('', '', '', '', '78000.89', '', '', '', '')
     000078000.89000  78000.89  ('', '', '', '', '78000.89', '', '', '', '')

string: '  .0457e10   .0457000e10   00000.0457000e10  '
            .0457e10  0.0457e10  ('', '', '', '.0457', '', 'e', '10', '', '')
         .0457000e10  0.0457e10  ('', '', '', '.0457', '', 'e', '10', '', '')
    00000.0457000e10  0.0457e10  ('', '', '', '.0457', '', 'e', '10', '', '')

string: '   258e8   2580000e4   0000000002580000e4   '
               258e8  258e8  ('', '258', '', '', '', 'e', '8', '', '')
           2580000e4  2580000e4  ('', '2580000', '', '', '', 'e', '4', '', '')
  0000000002580000e4  2580000e4  ('', '2580000', '', '', '', 'e', '4', '', '')

string: '  0.782e10   0000.782e10   0000.7820000e10  '
            0.782e10  0.782e10  ('', '', '', '.782', '', 'e', '10', '', '')
         0000.782e10  0.782e10  ('', '', '', '.782', '', 'e', '10', '', '')
     0000.7820000e10  0.782e10  ('', '', '', '.782', '', 'e', '10', '', '')

string: '  1.23E2   0001.23E2  0001.2300000E2   '
              1.23E2  1.23E2  ('', '', '', '', '1.23', 'E', '2', '', '')
           0001.23E2  1.23E2  ('', '', '', '', '1.23', 'E', '2', '', '')
      0001.2300000E2  1.23E2  ('', '', '', '', '1.23', 'E', '2', '', '')

string: '  432e-102  0000432e-102   004320000e-106   '
            432e-102  432e-102  ('', '432', '', '', '', 'e-', '102', '', '')
        0000432e-102  432e-102  ('', '432', '', '', '', 'e-', '102', '', '')
      004320000e-106  4320000e-106  ('', '4320000', '', '', '', 'e-', '106', '', '')

string: '  1.46e10and0001.46e10  0001.4600000e10   '
             1.46e10  1.46e10  ('', '', '', '', '1.46', 'e', '10', '', '')
          0001.46e10  1.46e10  ('', '', '', '', '1.46', 'e', '10', '', '')
     0001.4600000e10  1.46e10  ('', '', '', '', '1.46', 'e', '10', '', '')

string: '  1.077e-300  0001.077e-300  0001.077000e-300   '
          1.077e-300  1.077e-300  ('', '', '', '', '1.077', 'e-', '300', '', '')
       0001.077e-300  1.077e-300  ('', '', '', '', '1.077', 'e-', '300', '', '')
    0001.077000e-300  1.077e-300  ('', '', '', '', '1.077', 'e-', '300', '', '')

string: '  1.069e10   0001.069e10   0001.069000e10   '
            1.069e10  1.069e10  ('', '', '', '', '1.069', 'e', '10', '', '')
         0001.069e10  1.069e10  ('', '', '', '', '1.069', 'e', '10', '', '')
      0001.069000e10  1.069e10  ('', '', '', '', '1.069', 'e', '10', '', '')

string: '  105040.03e10  000105040.03e10  105040.0300e10    '
        105040.03e10  105040.03e10  ('', '', '', '', '105040.03', 'e', '10', '', '')
     000105040.03e10  105040.03e10  ('', '', '', '', '105040.03', 'e', '10', '', '')
      105040.0300e10  105040.03e10  ('', '', '', '', '105040.03', 'e', '10', '', '')

string: '  +286E000024.487900  -78.4500e.14500   .0140E789.  '
  +286E000024.487900  +286E24.4879  ('+', '286', '', '', '', 'E', '', '', '24.4879')
     -78.4500e.14500  -78.45e0.145  ('-', '', '', '', '78.45', 'e', '', '.145', '')
          .0140E789.  0.014E789  ('', '', '', '.014', '', 'E', '789', '', '')

string: '  081,12.40E07,95.0120     0045,78,123.03500e-0.00  '
081,12.40E07,95.0120  81,12.4E7,95.012  ('', '', '', '', '81,12.4', 'E', '', '', '7,95.012')
   0045,78,123.03500  45,78,123.035  ('', '', '', '', '45,78,123.035', '', '', '', '')

string: '  0096,78,473.0380e-0.    0008,78,373.066000E0.    0004512300.E0000  '
    0096,78,473.0380  96,78,473.038  ('', '', '', '', '96,78,473.038', '', '', '', '')
  0008,78,373.066000  8,78,373.066  ('', '', '', '', '8,78,373.066', '', '', '', '')
         0004512300.  4512300  ('', '4512300', '', '', '', '', '', '', '')

string: '  ..18000  25..00 36...77   2..8  '
           No match,  No catched string,  No groups.

string: '  3.8..9    .12500.     12.51.400  '
           No match,  No catched string,  No groups.

string: '  00099,111.8713000   -0012,45,83,987.26+0.000,099,88,44.or00,00,00.00must'
   00099,111.8713000  99,111.8713  ('', '', '', '', '99,111.8713', '', '', '', '')
  -0012,45,83,987.26  -12,45,83,987.26  ('-', '', '', '', '12,45,83,987.26', '', '', '', '')
         00,00,00.00  0  ('', '', '0', '', '', '', '', '', '')

string: '  00099,44,and   0000,099,88,44.bom'
           00099,44,  99,44  ('', '99,44', '', '', '', '', '', '', '')
     0000,099,88,44.  99,88,44  ('', '99,88,44', '', '', '', '', '', '', '')

string: '00,000,00.587000  77,98,23,45.,  this,that '
    00,000,00.587000  0.587  ('', '', '', '.587', '', '', '', '', '')
        77,98,23,45.  77,98,23,45  ('', '77,98,23,45', '', '', '', '', '', '', '')

string: '  ,111  145.20  +9,9,9  0012800  .,,.  1  100,000 '
                ,111  111  ('', '111', '', '', '', '', '', '', '')
              145.20  145.2  ('', '', '', '', '145.2', '', '', '', '')
              +9,9,9  +9,9,9  ('+', '9,9,9', '', '', '', '', '', '', '')
             0012800  12800  ('', '12800', '', '', '', '', '', '', '')
                   1  1  ('', '1', '', '', '', '', '', '', '')
             100,000  100,000  ('', '100,000', '', '', '', '', '', '', '')

string: '1,1,1.111  000,001.111   -999.  0.  111.110000  1.1.1.111  9.909,888'
           1,1,1.111  1,1,1.111  ('', '', '', '', '1,1,1.111', '', '', '', '')
         000,001.111  1.111  ('', '', '', '', '1.111', '', '', '', '')
               -999.  -999  ('-', '999', '', '', '', '', '', '', '')
                  0.  0  ('', '0', '', '', '', '', '', '', '')
          111.110000  111.11  ('', '', '', '', '111.11', '', '', '', '')
eyquem
fonte
8

O regex abaixo corresponderá a ambos os números do seu exemplo.

\b\d[\d,.]*\b

Ele retornará 5000 e 99.999.99998713 - correspondendo aos seus requisitos.

Leões
fonte
3
Isso corresponderá à vírgula em this,that.
Justin Morgan
@Justin Morgan - você está correto, eu não testei para essa condição. Aqui está uma versão atualizada que funcionará para todos os casos, exceto para um número que começa com uma vírgula ou ponto. \b\d[\d,.]+\b
Leons
Muito melhor, mas ainda permitirá 9....9ou 1,,,,X(embora o X não seja incluído na partida).
Justin Morgan
1
A propósito, \b\d[\d,.]*\bestá perto o suficiente para que, se você editar sua resposta, eu removesse o -1. Deve ser um * em vez de um +; \b\d[\d,.]+\bnão permite números de um único dígito.
Justin Morgan
@Justin Morgan - obrigado pelo insight. Esta questão era definitivamente mais complexa do que parecia. Atualizei minha resposta com base em seus comentários - faz sentido.
Leons
3

Tomando uma certa liberdade com os requisitos, você está procurando

\d+([\d,]?\d)*(\.\d+)?

Mas observe que isso corresponderá, por exemplo, 11,11,1

entonio
fonte
Por curiosidade, há algum motivo para você escolher em \d+([\d,]?\d)*(\.\d+)?vez de \d+(,\d+)*(\.\d+)?? Acho que dariam correspondências equivalentes, embora os grupos de captura fossem diferentes.
Justin Morgan
Oi. Sem motivo especial, foi uma suspensão de começar com uma expressão mais complexa para não corresponder a formatos inválidos.
entonio
3
\d+(,\d+)*(\.\d+)?

Isso pressupõe que sempre haja pelo menos um dígito antes ou depois de qualquer vírgula ou decimal e também pressupõe que haja no máximo um decimal e que todas as vírgulas precedam o decimal.

Neil
fonte
2
Isso não restringe os grupos de vírgulas ao formato de 3 dígitos. Ele vai aceitar 999999,9,9,9,9.
Justin Morgan
Embora eu provavelmente deva apontar que isso está mais perto de ser correto do que a maioria dos outros. Seu -1 não é de mim.
Justin Morgan
Esta é a ER que eu usaria, embora com outra etapa de validação posteriormente (possivelmente não com uma ER); tentar fazer tudo com um RE torna a vida muito mais difícil.
Donal Fellows
@Justin Morgan Não estava claro se a vírgula só era aceita em grupos de 3 dígitos. Mas isso é facilmente resolvido mudando (,\d+)para (,\d\d\d)eu acho.
Neil
2

Este regex:

(\d{1,3},\d{3}(,\d{3})*)(\.\d*)?|\d+\.?\d*

Correspondeu a todos os números da string:

1 1,0 0,1 1,001 1.000 1.000.000 1.000,1 1.000,1 1.323.444.000 1.999 1.222.455.666,0 1.244

Eric D
fonte
2

Aqui está uma regex:

(?:\d+)((\d{1,3})*([\,\ ]\d{3})*)(\.\d+)?

que aceita números:

  • sem espaços e / ou decimais, por exemplo. 123456789,123.123
  • com vírgulas ou espaços como separador de milhares e / ou decimais, por exemplo. 123 456 789, 123 456 789.100, 123,456,3,232,300,000.00

Testes: http://regexr.com/3h1a2

Kacper Cz
fonte
Isso funciona bem em regexr.com, mas no módulo python re não está funcionando
Pardhu
1

Aqui está outra construção que começa com o formato de número mais simples e, em seguida, de uma forma não sobreposta, adiciona progressivamente formatos de número mais complexos:

Java regep:

(\d)|([1-9]\d+)|(\.\d+)|(\d\.\d*)|([1-9]\d+\.\d*)|([1-9]\d{0,2}(,\d{3})+(\.\d*)?)

Como uma string Java (observe o \ extra necessário para escapar para \ e. Uma vez que \ e. Têm um significado especial em uma expressão regular quando por conta própria):

String myregexp="(\\d)|([1-9]\\d+)|(\\.\\d+)|(\\d\\.\\d*)|([1-9]\\d+\\.\\d*)|([1-9]\\d{0,2}(,\\d{3})+(\\.\\d*)?)";   

Explicação:

  1. Esta regexp tem a forma A | B | C | D | E | F onde A, B, C, D, E, F são as próprias regexps que não se sobrepõem. Geralmente, acho mais fácil começar com as correspondências mais simples possíveis, A. Se A perder as correspondências que você deseja, crie um B que seja uma pequena modificação de A e inclua um pouco mais do que você deseja. Então, com base em B, crie um C que capture mais, etc. Também acho mais fácil criar regexps que não se sobreponham; é mais fácil entender uma expressão regular com 20 expressões regulares não sobrepostas simples conectadas com ORs em vez de algumas expressões regulares com correspondência mais complexa. Mas, cada um com o seu!

  2. A é (\ d) e corresponde exatamente a 0,1,2,3,4,5,6,7,8,9 que não pode ser mais simples!

  3. B é ([1-9] \ d +) e corresponde apenas a números com 2 ou mais dígitos, o primeiro excluindo 0. B corresponde exatamente a um de 10,11,12, ... B não se sobrepõe a A, mas é uma pequena modificação de A.

  4. C é (. \ D +) e corresponde apenas a um decimal seguido por um ou mais dígitos. C corresponde exatamente a um de .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .00 .01 .02 .... .23000 ... C permite eros à direita, o que eu prefiro: se forem dados de medição, o número de zeros à direita indica o nível de precisão. Se você não quiser os zeros à direita, altere (. \ D +) para (. \ D * [1-9]), mas isso também exclui .0 que eu acho que deveria ser permitido. C também é uma pequena modificação de A.

  5. D é (\ d. \ D *) que é A mais decimais com zeros à direita. D corresponde apenas a um único dígito, seguido por um decimal, seguido por zero ou mais dígitos. D corresponde a 0. 0,0 0,1 0,2 ... 0,01000 ... 9. 9.0 9.1..0.0230000 .... 9.9999999999 ... Se você deseja excluir "0". em seguida, altere D para (\ d. \ d +). Se você quiser excluir zeros à direita, altere D para (\ d. \ D * [1-9]), mas isso exclui 2.0, que acho que deveria ser incluído. D não se sobrepõe a A, B ou C.

  6. E é ([1-9] \ d +. \ D *) que é B mais decimais com zeros à direita. Se você deseja excluir "13", por exemplo, altere E para ([1-9] \ d +. \ D +). E não se sobrepõe a A, B, C ou D. E corresponde a 10. 10.0 10.0100 .... 99.9999999999 ... Zeros à direita podem ser tratados como em 4. e 5.

  7. F é ([1-9] \ d {0,2} (, \ d {3}) + (. \ D *)?) E só combina números com vírgulas e possivelmente decimais, permitindo zeros à direita. O primeiro grupo ([1-9] \ d {0,2}) corresponde a um dígito diferente de zero seguido de zero, um ou mais dois dígitos. O segundo grupo (, \ d {3}) + corresponde a um grupo de 4 caracteres (uma vírgula seguida por exatamente três dígitos) e este grupo pode corresponder uma ou mais vezes (nenhuma correspondência significa que não há vírgulas!). Finalmente, (. \ D *)? não corresponde a nada ou corresponde. por si só ou corresponde a um decimal. seguido por qualquer número de dígitos, possivelmente nenhum. Novamente, para excluir itens como "1.111.", Altere (. \ D *) para (. \ D +). Zeros à direita podem ser tratados como em 4. ou 5. F não se sobrepõe a A, B, C, D ou E. Não consegui pensar em uma expressão regular mais fácil para F.

Deixe-me saber se você está interessado e posso editar acima para lidar com os zeros à direita conforme desejado.

Aqui está o que corresponde a regexp e o que não:

0
1
02 <- invalid
20
22
003 <- invalid
030 <- invalid
300
033 <- invalid
303
330
333
0004 <- invalid
0040 <- invalid
0400 <- invalid
4000
0044 <- invalid
0404 <- invalid
0440 <- invalid
4004
4040
4400
0444 <- invalid
4044
4404
4440
4444
00005 <- invalid
00050 <- invalid
00500 <- invalid
05000 <- invalid
50000
00055 <- invalid
00505 <- invalid
00550 <- invalid
05050 <- invalid
05500 <- invalid
50500
55000
00555 <- invalid
05055 <- invalid
05505 <- invalid
05550 <- invalid
50550
55050
55500
. <- invalid
.. <- invalid
.0
0.
.1
1.
.00
0.0
00. <- invalid
.02
0.2
02. <- invalid
.20
2.0
20.
.22
2.2
22.
.000
0.00
00.0 <- invalid
000. <- invalid
.003
0.03
00.3 <- invalid
003. <- invalid
.030
0.30
03.0 <- invalid
030. <- invalid
.033
0.33
03.3 <- invalid
033. <- invalid
.303
3.03
30.3
303.
.333
3.33
33.3
333.
.0000
0.000
00.00 <- invalid
000.0 <- invalid
0000. <- invalid
.0004
0.0004
00.04 <- invalid
000.4 <- invalid
0004. <- invalid
.0044
0.044
00.44 <- invalid
004.4 <- invalid
0044. <- invalid
.0404
0.404
04.04 <- invalid
040.4 <- invalid
0404. <- invalid
.0444
0.444
04.44 <- invalid
044.4 <- invalid
0444. <- invalid
.4444
4.444
44.44
444.4
4444.
.00000
0.0000
00.000 <- invalid
000.00 <- invalid
0000.0 <- invalid
00000. <- invalid
.00005
0.0005
00.005 <- invalid
000.05 <- invalid
0000.5 <- invalid
00005. <- invalid
.00055
0.0055
00.055 <- invalid
000.55 <- invalid
0005.5 <- invalid
00055. <- invalid
.00505
0.0505
00.505 <- invalid
005.05 <- invalid
0050.5 <- invalid
00505. <- invalid
.00550
0.0550
00.550 <- invalid
005.50 <- invalid
0055.0 <- invalid
00550. <- invalid
.05050
0.5050
05.050 <- invalid
050.50 <- invalid
0505.0 <- invalid
05050. <- invalid
.05500
0.5500
05.500 <- invalid
055.00 <- invalid
0550.0 <- invalid
05500. <- invalid
.50500
5.0500
50.500
505.00
5050.0
50500.
.55000
5.5000
55.000
550.00
5500.0
55000.
.00555
0.0555
00.555 <- invalid
005.55 <- invalid
0055.5 <- invalid
00555. <- invalid
.05055
0.5055
05.055 <- invalid
050.55 <- invalid
0505.5 <- invalid
05055. <- invalid
.05505
0.5505
05.505 <- invalid
055.05 <- invalid
0550.5 <- invalid
05505. <- invalid
.05550
0.5550
05.550 <- invalid
055.50 <- invalid
0555.0 <- invalid
05550. <- invalid
.50550
5.0550
50.550
505.50
5055.0
50550.
.55050
5.5050
55.050
550.50
5505.0
55050.
.55500
5.5500
55.500
555.00
5550.0
55500.
.05555
0.5555
05.555 <- invalid
055.55 <- invalid
0555.5 <- invalid
05555. <- invalid
.50555
5.0555
50.555
505.55
5055.5
50555.
.55055
5.5055
55.055
550.55
5505.5
55055.
.55505
5.5505
55.505
555.05
5550.5
55505.
.55550
5.5550
55.550
555.50
5555.0
55550.
.55555
5.5555
55.555
555.55
5555.5
55555.
, <- invalid
,, <- invalid
1, <- invalid
,1 <- invalid
22, <- invalid
2,2 <- invalid
,22 <- invalid
2,2, <- invalid
2,2, <- invalid
,22, <- invalid
333, <- invalid
33,3 <- invalid
3,33 <- invalid
,333 <- invalid
3,33, <- invalid
3,3,3 <- invalid
3,,33 <- invalid
,,333 <- invalid
4444, <- invalid
444,4 <- invalid
44,44 <- invalid
4,444
,4444 <- invalid
55555, <- invalid
5555,5 <- invalid
555,55 <- invalid
55,555
5,5555 <- invalid
,55555 <- invalid
666666, <- invalid
66666,6 <- invalid
6666,66 <- invalid
666,666
66,6666 <- invalid
6,66666 <- invalid
66,66,66 <- invalid
6,66,666 <- invalid
,666,666 <- invalid
1,111.
1,111.11
1,111.110
01,111.110 <- invalid
0,111.100 <- invalid
11,11. <- invalid
1,111,.11 <- invalid
1111.1,10 <- invalid
01111.11,0 <- invalid
0111.100, <- invalid
1,111,111.
1,111,111.11
1,111,111.110
01,111,111.110 <- invalid
0,111,111.100 <- invalid
1,111,111.
1,1111,11.11 <- invalid
11,111,11.110 <- invalid
01,11,1111.110 <- invalid
0,111111.100 <- invalid
0002,22.2230 <- invalid
.,5.,., <- invalid
2.0,345,345 <- invalid
2.334.456 <- invalid
David Alexander
fonte
1
\b\d+,

\ b -------> limite de palavra

\ d + ------> um ou dígito

, --------> contendo vírgulas,

Por exemplo:

sddsgg 70.000 sdsfdsf fdgfdg70,00

sfsfsd 5,44,4343 5,7788,44 555

Vai corresponder a:

70,

5,

44,

, 44

Ibz.Shaikh
fonte
0
(,*[\d]+,*[\d]*)+

Isso corresponderia a qualquer número pequeno ou grande como a seguir com ou sem vírgula

1
100
1,262
1,56,262
10,78,999
12,34,56,789

ou

1
100
1262
156262
1078999
123456789
phpnerd
fonte