Números combinados com expressões regulares – apenas dígitos e vírgulas

Eu não consigo descobrir como construir um regex para os valores de exemplo:

123,456,789 -12,34 1234 -8 

Você poderia me ajudar?

Se você quiser apenas permitir dígitos e vírgulas, ^[-,0-9]+$ é sua regex. Se você também quiser permitir espaços, use ^[-,0-9 ]+$ .

No entanto, se você quiser permitir números apropriados, é melhor usar algo assim:

 ^([-+] ?)?[0-9]+(,[0-9]+)?$ 

ou simplesmente use o analisador numérico de .net (para os vários NumberStyles, veja MSDN ):

 try { double.Parse(yourString, NumberStyle.Number); } catch(FormatException ex) { /* Number is not in an accepted format */ } 

O que é um número?

Eu tenho uma pergunta simples para a sua pergunta “simples”: o que exatamente você quer dizer com “um número”?

  • É um número?
  • Como você se sente com √−1 ?
  • É ou um número?
  • São 186,282.42±0.02 milhas / segundo um número – ou são dois ou três deles?
  • É 6.02e23 um número?
  • É 3.141_592_653_589 um número? Que tal π ou ? E −2π⁻³ ͥ ?
  • Quantos números em 0.083̄ ?
  • Quantos números em 128.0.0.1 ?
  • Que número mantém? Como sobre ⚂⚃ ?
  • 10,5 mm tem um número – ou tem dois?
  • É ∛8³ um número – ou são três deles?
  • Que número representa a ↀↀⅮⅭⅭⅬⅫ AUC , 2762 ou 2009?
  • São ४५६७ e ৭৮৯৮ números?
  • E quanto a 0377 , 0xDEADBEEF e 0b111101101 ?
  • Inf é um número? É NaN ?
  • ④② é um número? E sobre ?
  • Como você se sente com ?
  • O que tem a ver com números? Ou , e ?

Padrões Sugeridos

Além disso, você está familiarizado com esses padrões? Você pode explicar os prós e contras de cada um?

  1. /\D/
  2. /^\d+$/
  3. /^\p{Nd}+$/
  4. /^\pN+$/
  5. /^\p{Numeric_Value:10}$/
  6. /^\P{Numeric_Value:NaN}+$/
  7. /^-?\d+$/
  8. /^[+-]?\d+$/
  9. /^-?\d+\.?\d*$/
  10. /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
  11. /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
  12. /^((\d)(?(?=(\d))|$)(?(?{ord$3==1+ord$2})(?1)|$))$/
  13. /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/
  14. /^(?:(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}))$/
  15. /^(?:(?:[+-]?)(?:[0123456789]+))$/
  16. /(([+-]?)([0123456789]{1,3}(?:,?[0123456789]{3})*))/
  17. /^(?:(?:[+-]?)(?:[0123456789]{1,3}(?:,?[0123456789]{3})*))$/
  18. /^(?:(?i)(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$/
  19. /^(?:(?i)(?:[+-]?)(?:(?=[01]|[.])(?:[01]{1,3}(?:(?:[,])[01]{3})*)(?:(?:[.])(?:[01]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[01]+))|))$/
  20. /^(?:(?i)(?:[+-]?)(?:(?=[0123456789ABCDEF]|[.])(?:[0123456789ABCDEF]{1,3}(?:(?:[,])[0123456789ABCDEF]{3})*)(?:(?:[.])(?:[0123456789ABCDEF]{0,}))?)(?:(?:[G])(?:(?:[+-]?)(?:[0123456789ABCDEF]+))|))$/
  21. /((?i)([+-]?)((?=[0123456789]|[.])([0123456789]{1,3}(?:(?:[_,]?)[0123456789]{3})*)(?:([.])([0123456789]{0,}))?)(?:([E])(([+-]?)([0123456789]+))|))/

Eu suspeito que alguns desses padrões acima possam atender às suas necessidades. Mas eu não posso lhe dizer qual ou os outros – ou, se nenhum, lhe fornecer outro – porque você não disse o que quer dizer com “número”.

Como você pode ver, há um grande número de possibilidades numéricas: provavelmente, vale a pena, na verdade. ☺

Chave para os padrões sugeridos

Cada explicação numerada listada abaixo descreve o padrão do padrão numerado correspondente listado acima.

  1. Corresponder se houver algum não-dígito em qualquer lugar da string, incluindo espaços em branco como quebras de linha.
  2. Corresponda apenas se a cadeia contiver apenas dígitos, com a possível exceção de uma quebra de linha à direita. Observe que um dígito é definido como tendo a propriedade Número Decimal da Categoria Geral, que está disponível como \p{Nd} , \p{Decimal_Number} ou \p{General_Category=Decimal_Number} . Este turno é, na verdade, apenas um reflexo dos pontos de código cuja categoria Tipo Numérico é Decimal, que está disponível como \p{Numeric_Type=Decimal} .
  3. Isso é o mesmo que 2 na maioria dos idiomas regex. Java é uma exceção aqui, porque não mapeia as fugas de charclass simples como \w e \W , \d e \D , \s e \S e \b ou \B na propriedade Unicode apropriada. Isso significa que você não deve usar nenhum desses oito escapes de um caractere para quaisquer dados Unicode em Java, porque eles funcionam apenas em ASCII, embora o Java sempre use caracteres Unicode internamente.
  4. Isso é um pouco diferente de 3, pois não está limitado a números decimais, mas pode ser qualquer número; ou seja, qualquer caractere com a propriedade \pN , \p{Number} ou \p{General_Category=Number} . Estes incluem \p{Nl} ou \p{Letter_Number} para números como algarismos romanos e \p{No} ou \p{Other_Number} para números subscritos e subscritos, frações e números circulados – entre outros, como barras de contagem.
  5. Isto corresponde apenas àquelas strings compostas inteiramente de números cujo valor decimal é 10, então coisas como o numeral romano dez, e , , , , , , e .
  6. Apenas as strings que contêm caracteres que não possuem o Valor Numérico NaN; Em outras palavras, todos os caracteres devem ter algum valor numérico.
  7. Corresponde apenas a números decimais, opcionalmente com um HYPHEN MINUS.
  8. O mesmo que 7, mas agora também funciona se o sinal for mais em vez de menos.
  9. Procura números decimais, com HYPHEN MINUS opcional e STOP COMPLETO opcional, além de zero ou mais números decimais a seguir.
  10. O mesmo que 9, mas não requer dígitos antes do ponto, se tiver algum depois.
  11. Notação de ponto flutuante padrão por C e muitas outras linguagens, permitindo a notação científica.
  12. Encontra números compostos apenas de duas ou mais casas decimais de qualquer script em ordem decrescente, como 987 ou 54321. Essa regex recursiva inclui uma chamada para o código Perl que verifica se o dígito de antecipação tem um valor de ponto de código que é o sucessor do dígito atual ; isto é, seu valor ordinal é um maior. Pode-se fazer isso no PCRE usando uma function C como callout.
  13. Isso procura um endereço IPv4 válido com quatro números decimais no intervalo válido, como 128.0.0.1 ou 255.255.255.240, mas não 999.999.999.999.
  14. Isso procura um endereço MAC válido, portanto, seis pares separados por dois pontos de dois dígitos hexadecimais ASCII.
  15. Isso procura números inteiros na faixa ASCII com um sinal principal opcional. Este é o padrão normal para correspondência de inteiros ASCII.
  16. Isto é como 15, exceto que requer uma vírgula para separar grupos de três.
  17. Isso é como 15, exceto que a vírgula para separar grupos agora é opcional.
  18. Esse é o padrão normal para a correspondência de números de ponto flutuante no estilo C em ASCII.
  19. Isto é como 18, mas requer uma vírgula para separar grupos de 3 e em base-2 em vez de em base-10.
  20. Isto é como 19, mas em hexadecimal. Observe que o expoente opcional é agora indicado por um G em vez de um E, já que E é um dígito hexadecimal válido.
  21. Isso verifica se a cadeia contém um número de ponto flutuante no estilo C, mas com um separador de agrupamento opcional a cada três dígitos de uma vírgula ou um sublinhado (LINHA BAIXA) entre eles. Ele também armazena essa cadeia no grupo de captura \1 , disponibilizando $1 após o sucesso da partida.

Fontes e manutenibilidade

Os padrões 1,2,7-11 vêm de uma versão anterior da lista de Perguntas Frequentes do Perl na pergunta “Como validar input?”. Essa seção foi substituída por uma sugestão para usar o módulo Regexp :: Common , escrito por Abigail e Damian Conway . Os padrões originais ainda podem ser encontrados na Receita 2.1 do Perl Cookbook , “Verificando se uma String é um Número Válido”, soluções que podem ser encontradas para um número estonteante de diversos idiomas, incluindo ada, common lisp, groovy, guile, haskell, java, merd, ocaml, php, pique, python, rexx, ruby ​​e tcl no projeto PLEAC .

Padrão 12 poderia ser reescrito de maneira mais legível

 m{ ^ ( ( \d ) (?(?= ( \d ) ) | $ ) (?(?{ ord $3 == 1 + ord $2 }) (?1) | $ ) ) $ }x 

Ele usa a recursion regex , que é encontrada em muitos mecanismos de padrão, incluindo o Perl e todas as linguagens derivadas do PCRE. Mas também usa um callout de código embutido como o teste de seu segundo padrão condicional; Pelo que sei, as chamadas de código estão disponíveis apenas em Perl e PCRE.

Os padrões 13 a 21 foram derivados do módulo Regexp :: Common mencionado anteriormente. Observe que, por brevidade, todas elas são escritas sem o espaço em branco e os comentários que você definitivamente deseja no código de produção. Aqui está como isso pode parecer no modo /x :

 $real_rx = qr{ ( # start $1 to hold entire pattern ( [+-]? ) # optional leading sign, captured into $2 ( # start $3 (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead ( # start $4 [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end $4 (?: # begin optional cluster ( [.] ) # required literal dot in $5 ( [0123456789]{0,} ) # then optional ASCII digits in $6 ) ? # end optional cluster ) # end $3 (?: # begin cluster group ( [E] ) # base-10 exponent into $7 ( # exponent number into $8 ( [+-] ? ) # optional sign for exponent into $9 ( [0123456789] + ) # one or more ASCII digits into $10 ) # end $8 | # or else nothing at all ) # end cluster group ) }xi; # end $1 and whole pattern, enabling /x and /i modes 

Do ponto de vista da engenharia de software, ainda há vários problemas com o estilo usado na versão do modo /x imediatamente acima. Primeiro, há uma grande quantidade de repetição de código, onde você vê o mesmo [0123456789] ; o que acontece se uma dessas sequências deixar acidentalmente um dígito? Segundo, você está confiando em parâmetros posicionais, que você deve contar. Isso significa que você pode escrever algo como:

 ( $real_number, # $1 $real_number_sign, # $2 $pre_exponent_part, # $3 $pre_decimal_point, # $4 $decimal_point, # $5 $post_decimal_point, # $6 $exponent_indicator, # $7 $exponent_number, # $8 $exponent_sign, # $9 $exponent_digits, # $10 ) = ($string =~ /$real_rx/); 

que é francamente abominável! É fácil obter a numeração errada, difícil lembrar que nomes simbólicos vão para onde, e tedioso para escrever, especialmente se você não precisa de todas essas partes. Reescrevendo isso para usar grupos nomeados em vez de apenas os numerados. Novamente, usarei a syntax Perl para as variables, mas o conteúdo do Pattern deverá funcionar em qualquer lugar em que os grupos nomeados sejam suportados.

 use 5.010; # Perl got named patterns in 5.10 $real_rx = qr{ (? # optional leading sign (? [+-]? ) (? (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead (? [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end  (?: # begin optional anon cluster (? [.] ) # required literal dot (? [0123456789]{0,} ) ) ? # end optional anon cluster ) # end  # begin anon cluster group: (?: (? [E] ) # base-10 exponent (? # exponent number (? [+-] ? ) (? [0123456789] + ) ) # end  | # or else nothing at all ) # end anon cluster group ) # end  }xi; 

Agora as abstrações são nomeadas, o que ajuda. Você pode puxar os grupos pelo nome e só precisa dos que você gosta. Por exemplo:

 if ($string =~ /$real_rx/) { ($pre_exponent, $exponent_number) = @+{ qw< pre_exponent exponent_number > }; } 

Há mais uma coisa para fazer esse padrão para torná-lo ainda mais sustentável. O problema é que ainda há muita repetição, o que significa que é muito fácil mudar em um lugar, mas não em outro. Se você estivesse fazendo uma análise de McCabe, diria que sua métrica de complexidade é muito alta. A maioria de nós diria que é muito recuado. Isso dificulta seguir. Para consertar todas essas coisas, o que precisamos é de um “padrão gramatical”, um com um bloco de definição para criar abstrações nomeadas, que depois tratamos mais ou menos como uma chamada de subrotina mais tarde na partida.

 use 5.010; # Perl first got regex subs in v5.10 $real__rx = qr{ ^ # anchor to front (?&real_number) # call &real_number regex sub $ # either at end or before final newline ################################################## # the rest is definition only; think of ## # each named buffer as declaring a subroutine ## # by that name ## ################################################## (?(DEFINE) (? (?&mantissa) (?&abscissa) ? ) (? (?&exponent_indicator) (?&exponent) ) (? (&?sign) ? (?&a_digit) + ) (? # expecting either of these.... (?= (?&a_digit) | (?&point) ) (?&a_digit) {1,3} (?: (?&digit_separator) ? (?&a_digit) {3} ) * (?: (?&point) (?&a_digit) * ) ? ) (? [.] ) (? [+-] ) (? [_,] ) (? [Ee] ) (? [0-9] ) ) # end DEFINE block }x; 

Veja quão incrivelmente melhor é o padrão gramatical do que o padrão original de ruído de linha? Também é muito mais fácil obter a syntax correta: digitei isso sem até mesmo um erro de syntax de regex que precisava ser corrigido. (OK bem, eu digitei todos os outros sem nenhum erro de syntax, mas eu tenho feito isso por um tempo 🙂

Os padrões gramaticais parecem muito mais com uma FBN do que com as antigas expressões regulares que as pessoas vêm odiar. Eles são muito mais fáceis de ler, escrever e manter. Então, não vamos ter mais padrões feios, ok?

Tente isto:

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

Permite:

 1 12 .99 12.34 -18.34 12,345.67 999,999,999,999,999.99 

Como essa questão foi reaberta quatro anos depois, gostaria de oferecer uma visão diferente. Como alguém gasta muito tempo trabalhando com regex, minha opinião é a seguinte:

A. Se possível, não use Regex para validar números

Se possível, use seu idioma. Pode haver funções para ajudá-lo a determinar se o valor contido por uma string é um número válido. Dito isto, se você está aceitando uma variedade de formatos (vírgulas, etc), você pode não ter escolha.

B. Não escreva o Regex manualmente para validar um intervalo de numeração

  • Escrever um regex para corresponder a um número em um determinado intervalo é difícil. Você pode cometer um erro ao escrever um regex para corresponder a um número entre 1 e 10 .
  • Depois de ter um regex para um intervalo de numeração, é difícil depurá-lo. Primeiro, é horrível de se olhar. Segundo, como você pode ter certeza de que corresponde a todos os valores desejados sem corresponder a nenhum dos valores que você não deseja? Francamente, se você está sozinho, sem colegas olhando por cima do seu ombro, você não pode. A melhor técnica de debugging é produzir um intervalo inteiro de números programaticamente e verificá-los em relação ao regex.
  • Felizmente, existem ferramentas para gerar um regex para um intervalo numérico automaticamente.

C. Gaste seu Regex Energy com sabedoria: use ferramentas

  • Números correspondentes em um determinado intervalo é um problema que foi resolvido. Não há necessidade de você tentar reinventar a roda. É um problema que pode ser resolvido mecanicamente, por um programa, de uma forma que é garantida para ser livre de erros. Aproveite esse passeio grátis.
  • Resolver um regex de intervalo de números pode ser interessante para fins de aprendizado algumas vezes. Além disso, se você tiver energia para investir no aprimoramento de suas habilidades de regex, use-a em algo útil, como aprofundar sua compreensão da ganância regex , ler regex Unicode , jogar com correspondências de largura zero ou recursion, lendo o SO regex FAQ e descobrir truques legais, como excluir certos padrões de uma correspondência de expressão regular … ou ler clássicos como Expressões Regulares Mateing, 3rd Ed ou The Cookbook Expressões regulares, 2nd Ed .

Para ferramentas, você pode usar:

  • Online: Regex_for_range
  • Offline: o único que eu conheço é o RegexMagic (não gratuito) pelo regex guru Jan Goyvaerts. É o seu produto regex para principiantes e, se bem me lembro, tem uma grande variedade de opções para gerar números num determinado intervalo, entre outras funcionalidades.
  • Se as condições forem muito complexas, gere automaticamente dois intervalos … depois junte-os a um operador de alternância |

D. Um Exercício: Construindo um Regex para as Especificações na Pergunta

Essas especificações são bem amplas … mas não necessariamente vagas. Vamos ver os valores de amostra novamente:

 123,456,789 -12,34 1234 -8 

Como os dois primeiros valores se relacionam? No primeiro, a vírgula combina grupos de potências de três. No segundo, provavelmente corresponde ao ponto decimal em um formato numérico de estilo europeu-continental. Isso não significa que devemos permitir dígitos em todos os lugares, como em 1,2,3,44 . Da mesma forma, não devemos ser restritivos. O regex na resposta aceita, por exemplo, não corresponderá a um dos requisitos, 123,456,789 (ver demonstração ).

Como podemos construir nosso regex para corresponder às especificações?

  • Vamos ancorar a expressão entre ^ e $ para evitar subnomes
  • Vamos permitir um sinal de menos opcional: -?
  • Vamos combinar dois tipos de números em ambos os lados de uma alternação (?:this|that) :
  • À esquerda, um dígito ao estilo europeu com vírgula opcional para a parte decimal: [1-9][0-9]*(?:,[0-9]+)?
  • À direita, um número com milhares de separadores: [1-9][0-9]{1,2}(?:,[0-9]{3})+

O regex completo:

 ^-?(?:[1-9][0-9]*(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$ 

Veja demonstração .

Essa regex não permite números em estilo europeu começando com 0 , como 0,12 . É uma característica, não um bug. Para combinar com isso também, um pequeno ajuste fará:

 ^-?(?:(?:0|[1-9][0-9]*)(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$ 

Veja demonstração .

Tente isto:

 ^-?[\d\,]+$ 

Ele permitirá um opcional - como o primeiro caractere e, em seguida, qualquer combinação de vírgulas e dígitos.

 ^-? # start of line, optional - (\d+ # any number of digits |(\d{1,3}(,\d{3})*)) # or digits followed by , and three digits ((,|\.)\d+)? # optional comma or period decimal point and more digits $ # end of line 
 ^[-+]?(\d{1,3})(,?(?1))*$ 

Visualização de expressão regular

Debuggex Demo

Então, o que isso ?!

  • ^ marca o começo da corda
  • [-+]? permite um sinal de menos ou mais logo após o início da string
  • (\d{1,3}) corresponde a pelo menos um e no máximo três ( {1,3} ) dígitos ( \d – geralmente [0-9] ) em uma linha e os agrupa (os parênteses (...) criados o grupo) como o primeiro grupo
  • (,?(?1))* Ok (,?(?1))* ok … vamos quebrar isso
    • (...) constrói outro grupo ( não tão importante )
    • ,? corresponde a uma vírgula (se existente) logo após a primeira seqüência de dígitos
    • (?1) corresponde ao padrão do primeiro grupo novamente (lembre-se (\d{1,3}) ); em palavras: neste ponto, a expressão corresponde a um sinal (mais / menos / nenhum) seguido por uma seqüência de dígitos, possivelmente seguida por uma vírgula, seguida por outra seqüência de dígitos novamente.
    • (,?(?1))* , o * repete a segunda parte (vírgula e seqüência) com a maior freqüência possível
  • $ finalmente corresponde ao final da string

a vantagem de tais expressões é, para evitar definir o mesmo padrão dentro de sua expressão de novo e de novo e de novo … bem, uma desvantagem é algumas vezes a complexidade: – /

Em java, você pode usar java.util.Scanner com seu método useLocale

 Scanner myScanner = new Scanner(input).useLocale( myLocale) isADouble = myScanner.hasNextDouble() 

Para os exemplos:

  ^(-)?([,0-9])+$ 

Deve funcionar. Implemente-o em qualquer idioma desejado.

Tente isto:

  boxValue = boxValue.replace(/[^0-9\.\,]/g, ""); 

Este RegEx corresponderá apenas a dígitos, pontos e vírgulas.