Eu tenho uma tarefa para combinar números de ponto flutuante. Escrevi a seguinte expressão regular para ele:
[-+]?[0-9]*\.?[0-9]*
Mas, ele retorna um erro:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
De acordo com meu conhecimento, precisamos usar um caractere de escape para o .
também. Por favor, corrija-me onde estou errado.
(?:\d+(?:\.\d*)?|\.\d+)
e tem sido postado ad infinitum no SO ...[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?
se você deseja capturar a notação exponencial também, por exemplo, 3.023e-23Respostas:
TL; DR
Use em
[.]
vez de\.
e em[0-9]
vez de\d
para evitar problemas de escape em algumas linguagens (como Java).Obrigado ao anônimo por originalmente reconhecer isso.
Um padrão relativamente simples para combinar um número de ponto flutuante é
Isso vai corresponder a:
123
123.456
.456
Veja um exemplo funcional
Se você também quiser fazer a correspondência
123.
(um ponto sem parte decimal), precisará de uma expressão um pouco mais longa:Veja a resposta de pkeller para uma explicação mais completa deste padrão
Se você deseja incluir números não decimais, como hexadecimal e octal, consulte minha resposta a Como posso identificar se uma string é um número? .
Se você deseja validar que uma entrada é um número (em vez de encontrar um número na entrada), você deve cercar o padrão com
^
e$
, assim:Expressões regulares irregulares
As "expressões regulares", conforme implementadas na maioria das linguagens modernas, APIs, frameworks, bibliotecas, etc., são baseadas em um conceito desenvolvido na teoria da linguagem formal . No entanto, os engenheiros de software adicionaram muitas extensões que levam essas implementações muito além da definição formal. Portanto, embora a maioria dos mecanismos de expressão regular sejam semelhantes, na verdade não existe um padrão. Por isso, depende muito de qual linguagem, API, framework ou biblioteca você está usando.
(A propósito, para ajudar a reduzir a confusão, muitos passaram a usar " regex " ou " regexp " para descrever essas linguagens de correspondência aprimoradas. Consulte Regex é o mesmo que uma expressão regular? Em RexEgg.com para obter mais informações.)
Dito isso, a maioria dos motores de regex (na verdade, todos eles, pelo que eu sei) aceitariam
\.
. Provavelmente, há um problema com o escape.O problema de escapar
Algumas linguagens têm suporte integrado para regexes, como JavaScript . Para aquelas linguagens que não o fazem, o escape pode ser um problema.
Isso ocorre porque você basicamente está codificando em um idioma dentro de outro idioma. Java, por exemplo, usa
\
como um caractere de escape dentro de suas strings, então se você quiser colocar um caractere literal de barra invertida em uma string, você deve escapar dele:No entanto, regexes também usam o
\
caractere para escape, portanto, se você quiser corresponder a um\
caractere literal , deverá escapar dele para o mecanismo de regexe e, em seguida, escapar novamente para Java:No seu caso, você provavelmente não escapou do caractere de barra invertida na linguagem em que está programando:
Toda essa fuga pode ser muito confusa. Se a linguagem com a qual você está trabalhando suporta strings brutas , então você deve usá-las para reduzir o número de barras invertidas, mas nem todas as linguagens suportam (mais notavelmente: Java). Felizmente, há uma alternativa que funcionará algumas vezes:
Para um motor regex,
\.
e[.]
significa exatamente a mesma coisa. Observe que isso não funciona em todos os casos, como nova linha (\\n
), colchete de abertura (\\[
) e barra invertida (\\\\
ou[\\]
).Uma nota sobre números correspondentes
(Dica: é mais difícil do que você pensa)
Combinar um número é uma daquelas coisas que você acha que é muito fácil com regex, mas na verdade é bem complicado. Vamos dar uma olhada em sua abordagem, peça por peça:
Combine um opcional
-
ou+
Corresponde a 0 ou mais dígitos sequenciais
Combine um opcional
.
Corresponde a 0 ou mais dígitos sequenciais
Primeiro, podemos limpar essa expressão um pouco usando uma abreviação de classe de caractere para os dígitos (observe que isso também é suscetível ao problema de escape mencionado acima):
[0-9]
=\d
Vou usar
\d
abaixo, mas lembre-se de que significa a mesma coisa que[0-9]
. (Bem, na verdade, em alguns mecanismos\d
corresponderá dígitos de todos os scripts, portanto, corresponderá mais do que[0-9]
, mas isso provavelmente não é significativo no seu caso.)Agora, se você observar isso com atenção, perceberá que cada parte do seu padrão é opcional . Esse padrão pode corresponder a uma string de comprimento 0; uma corda composta apenas por
+
ou-
; ou, uma corda composta apenas por a.
. Provavelmente não é o que você pretendia.Para corrigir isso, é útil começar "ancorando" sua regex com a string mínima necessária, provavelmente um único dígito:
Agora queremos adicionar a parte decimal, mas ela não vai para onde você pensa que poderia:
Isso ainda corresponderá a valores como
123.
. Pior, tem um toque de maldade nisso. O período é opcional, o que significa que você tem duas classes repetidas lado a lado (\d+
e\d*
). Na verdade, isso pode ser perigoso se usado da maneira errada, deixando seu sistema vulnerável a ataques DoS.Para corrigir isso, em vez de tratar o período como opcional, precisamos tratá-lo como obrigatório (para separar as classes de caracteres repetidos) e, em vez disso, tornar opcional toda a parte decimal:
Isso está parecendo melhor agora. Exigimos um período entre a primeira sequência de dígitos e a segunda, mas há uma falha fatal: não podemos fazer a correspondência
.123
porque um dígito inicial agora é necessário.Na verdade, isso é muito fácil de consertar. Em vez de tornar opcional a parte "decimal" do número, precisamos olhar para ela como uma sequência de caracteres: 1 ou mais números que podem ser prefixados por um
.
que pode ser prefixado por 0 ou mais números:Agora apenas adicionamos o sinal:
Claro, essas barras são muito irritantes em Java, então podemos substituí-las em nossas classes de caracteres de formato longo:
Correspondência versus validação
Isso já apareceu nos comentários algumas vezes, então estou adicionando um adendo sobre correspondência versus validação.
O objetivo da correspondência é encontrar algum conteúdo na entrada (a "agulha em um palheiro"). O objetivo da validação é garantir que a entrada esteja em um formato esperado.
Regexes, por sua natureza, só correspondem a texto. Com alguma entrada, eles encontrarão algum texto correspondente ou não. No entanto, ao "encaixar" uma expressão no início e no final da entrada com marcas âncora (
^
e$
), podemos garantir que nenhuma correspondência seja encontrada a menos que toda a entrada corresponda à expressão, usando efetivamente regexes para validar .A regex descrita acima (
[+-]?([0-9]*[.])?[0-9]+
) corresponderá a um ou mais números em uma string de destino. Então, dada a entrada:A regex irá corresponder
1.34
,7.98
,1.2
,.3
e.4
.Para validar que uma determinada entrada é um número e nada além de um número, "encaixe" a expressão no início e no final da entrada envolvendo-a em tags âncora:
Isso só encontrará uma correspondência se a entrada inteira for um número de ponto flutuante e não encontrará uma correspondência se a entrada contiver caracteres adicionais. Portanto, dada a entrada
1.2
, uma correspondência será encontrada, masapple 1.2 pear
nenhuma correspondência será encontrada.Observe que alguns motores de regex têm uma função
validate
,isMatch
ou semelhante, que essencialmente faz o que descrevi automaticamente, retornandotrue
se uma correspondência for encontrada efalse
se nenhuma correspondência for encontrada. Também tenha em mente que alguns mecanismos permitem que você defina sinalizadores que alteram a definição de^
e$
, correspondendo ao início / fim de uma linha ao invés do início / fim de toda a entrada. Normalmente, esse não é o padrão, mas fique atento a esses sinalizadores.fonte
\d+(\.\d*)?|\.\d+
/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
1.
corresponde. Adicione^
e$
ao início e ao final da regex se desejar corresponder apenas se toda a entrada corresponder.[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))
e / d para float / float de precisão dupla. Não se esqueça de um sinalizador de caixa dobrável para a regexEu não acho que nenhuma das respostas nesta página no momento da escrita esteja correta (muitas outras sugestões em outras partes do SO também estão erradas). A complicação é que você precisa combinar todas as seguintes possibilidades:
0.35
,22.165
)0.
,1234.
).0
,.5678
)Ao mesmo tempo, você deve garantir que haja pelo menos um dígito em algum lugar, ou seja, o seguinte não é permitido:
+.
ou seja, ou-.
)+
ou-
por conta própriaIsso parece complicado no início, mas uma maneira de encontrar inspiração é olhar o código-fonte do OpenJDK para o
java.lang.Double.valueOf(String)
método (comece em http://hg.openjdk.java.net/jdk8/jdk8/jdk , clique em "navegar", navegue para baixo/src/share/classes/java/lang/
e encontrar aDouble
classe). A longa regex que esta classe contém atende a várias possibilidades que o OP provavelmente não tinha em mente, mas ignorando para simplificar as partes que lidam com NaN, infinito, notação hexadecimal e expoentes, e usando\d
em vez da notação POSIX para um único dígito, posso reduzir as partes importantes da regex para um número de ponto flutuante assinado sem expoente para:[+-]?((\d+\.?\d*)|(\.\d+))
Não creio que haja como evitar a
(...)|(...)
construção sem permitir algo que não contenha algarismos, ou proibir uma das possibilidades que não tem algarismos antes da vírgula ou nenhum algarismo depois dela.Obviamente, na prática, você precisará fornecer espaços em branco à direita ou precedentes, no próprio regex ou no código que o utiliza.
fonte
123.
, então sim ... a opção ou é a única solução, como indiquei em um comentário em meu post original.[+-]?((?=\.?\d)\d*\.?\d*)
ser usada para evitar a alternância? Ele usa um lookahead ...o que você precisa é:
Eu escapei do sinal "+" e "-" e também agrupei o decimal com seus dígitos seguintes, já que algo como "1". não é um número válido.
As mudanças permitirão que você combine inteiros e flutuantes. por exemplo:
fonte
.1
não seria permitida, embora tal entrada seja universalmente reconhecida como correta.-
e+
, que não são números. Regex é complicado! :)\.
não funciona.Eu quero combinar o que a maioria das línguas considera números válidos (inteiros e flutuantes):
'5' / '-5'
'1.0' / '1.' / '.1' / '-1.' / '-.1'
'0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'
Notas:
preceding sign of number ('-' or '+') is optional
'-1.' and '-.1' are valid but '.' and '-.' are invalid
'.1e3' is valid, but '.e3' and 'e3' are invalid
Para oferecer suporte a '1' e '.1' precisamos de um operador OR ('|') para garantir a exclusão de '.' de combinar.
[+-]?
+/- cantar é opcional, pois?
significa 0 ou 1 correspondência(
uma vez que temos 2 subexpressões, precisamos colocá-las entre parênteses\d+([.]\d*)?(e[+-]?\d+)?
Isso é para números que começam com um dígito|
separa subexpressões[.]\d+(e[+-]?\d+)?
isso é para números começando com '.')
fim das expressões[.]
o primeiro caractere é um ponto (entre colchetes ou então é um caractere curinga)\d+
um ou mais dígitos(e[+-]?\d+)?
esta é uma notação científica opcional (0 ou 1 correspondências devido à terminação '?')\d+
um ou mais dígitos([.]\d*)?
opcionalmente, podemos ter um caractere de ponto e zero ou mais dígitos após ele(e[+-]?\d+)?
esta é uma notação científica opcionale
literal que especifica o expoente[+-]?
sinal de expoente opcional\d+
um ou mais dígitosTodos aqueles combinados:
Para aceitar
E
também:( Casos de teste )
fonte
É simples: você usou Java e deve usar em
\\.
vez de\.
(pesquise por escape de caractere em Java).fonte
Este funcionou para mim:
Você também pode usar este (sem parâmetro nomeado):
Use algum testador de regex online para testá-lo (por exemplo, regex101)
fonte
Isso vai corresponder a:
fonte
[+-]?
- sinal de liderança opcional(([1-9][0-9]*)|(0))
- inteiro sem zero à esquerda, incluindo zero único([.,][0-9]+)?
- parte fracionária opcionalfonte
Em C ++ usando a biblioteca regex
A resposta seria assim:
Observe que eu não pego o símbolo do sinal, se você quisesse com o símbolo do sinal, faria o seguinte:
Isso também separa um número normal ou um número decimal.
fonte
Na notação c, o número flutuante pode ocorrer nas seguintes formas:
Para criar a expressão regular float, primeiro criarei "variável de expressão regular int":
Agora, vou escrever pequenos pedaços de expressão regular de float - a solução é concatá-los com o símbolo "|".
Pedaços:
Solução final (concanando pequenos pedaços):
fonte
Experimente esta solução.
fonte
para javascript
O que funcionaria para 1,23 1234,22 0 0,12 12
Você pode alterar as partes no
{}
para obter resultados diferentes no comprimento decimal e na frente do decimal também. Isso é usado em entradas para inserir o número e verificar cada entrada conforme você digita, permitindo apenas o que passa.fonte