Qual é a maneira mais limpa e eficaz de validar números decimais em JavaScript?
Pontos de bônus por:
- Clareza. A solução deve ser limpa e simples.
- Plataforma cruzada.
Casos de teste:
01. IsNumeric('-1') => true
02. IsNumeric('-1.5') => true
03. IsNumeric('0') => true
04. IsNumeric('0.42') => true
05. IsNumeric('.42') => true
06. IsNumeric('99,999') => false
07. IsNumeric('0x89f') => false
08. IsNumeric('#abcdef') => false
09. IsNumeric('1.2.3') => false
10. IsNumeric('') => false
11. IsNumeric('blah') => false
javascript
validation
numbers
Michael Haren
fonte
fonte
jQuery.isNumeric
função de utilitário: api.jquery.com/jQuery.isNumericjQuery.isNumeric
falhará no sétimo caso de teste do OP (IsNumeric('0x89f') => *false*
). Não tenho certeza se concordo com este caso de teste, no entanto.Respostas:
A resposta de @ Joel é bem próxima, mas falhará nos seguintes casos:
Algum tempo atrás, eu tive que implementar uma
IsNumeric
função, para descobrir se uma variável continha um valor numérico, independentemente de seu tipo , poderia ser umaString
contendo um valor numérico (eu tinha que considerar também notação exponencial etc.), umNumber
objeto, praticamente qualquer coisa poderia ser passada para essa função, eu não podia fazer nenhuma suposição de tipo, cuidando da coerção de tipo (por exemplo,+true == 1;
mastrue
não deveria ser considerado como"numeric"
).Eu acho que vale a pena compartilhar esse conjunto de +30 testes de unidade feitos em várias implementações de funções e também compartilhar o que passa em todos os meus testes:
PS isNaN e isFinite têm um comportamento confuso devido à conversão forçada em número. No ES6, Number.isNaN e Number.isFinite corrigiam esses problemas. Lembre-se disso ao usá-los.
Atualização : Veja como o jQuery faz isso agora (2.2-estável) :
Atualização : Angular 4.3 :
fonte
2e308 > Number.MAX_VALUE
desde2e308 == Infinity
. Se você deseja uma função que retornetrue
também para valores de infinito positivo e negativo, verifique a função número 2 no conjunto de testes . Felicidades.Arrrgh! Não dê ouvidos às respostas da expressão regular. RegEx é nojento por isso, e não estou falando apenas de desempenho. É muito fácil cometer erros sutis, impossíveis de detectar com sua expressão regular.
Se você não pode usar
isNaN()
, isso deve funcionar muito melhor:Veja como funciona:
A
(input - 0)
expressão força o JavaScript a fazer coerção de tipo no seu valor de entrada; ele deve primeiro ser interpretado como um número para a operação de subtração. Se essa conversão para um número falhar, a expressão resultará emNaN
. Esse resultado numérico é então comparado ao valor original que você digitou. Como o lado esquerdo agora é numérico, a coerção de tipo é novamente usada. Agora que a entrada de ambos os lados foi coagida para o mesmo tipo a partir do mesmo valor original, você pensaria que elas sempre deveriam ser as mesmas (sempre verdadeiras). No entanto, existe uma regra especial que diz queNaN
nunca é igual aNaN
, portanto, um valor que não pode ser convertido em um número (e apenas valores que não podem ser convertidos em números) resultará em falso.A verificação do comprimento é para um caso especial envolvendo seqüências de caracteres vazias. Observe também que ele cai no teste 0x89f, mas isso ocorre em muitos ambientes, que é uma boa maneira de definir um literal numérico. Se você quiser capturar esse cenário específico, poderá adicionar uma verificação adicional. Melhor ainda, se esse é o seu motivo para não usar
isNaN()
, basta agrupar sua própria funçãoisNaN()
que também pode fazer a verificação adicional.Em resumo, se você quiser saber se um valor pode ser convertido em um número, tente convertê-lo em um número.
Voltei e fiz algumas pesquisas para saber por que uma string de espaço em branco não tinha a saída esperada e acho que a entendi agora: uma string vazia é coagida em
0
vez deNaN
. Basta aparar a corda antes que a verificação do comprimento lide com esse caso.A execução dos testes de unidade com o novo código e ele falha apenas nos literais infinito e booleano, e o único momento que deve ser um problema é se você está gerando código (realmente, quem digitaria um literal e verificaria se é numérico? Você deve saber ), e isso seria um código estranho para gerar.
Mas, novamente, o único motivo para usar isso é se, por algum motivo, você deve evitar isNaN ().
fonte
IsNumeric(' ')
,IsNumeric('\n\t')
, etc todo o retornotrue
Number
literais;IsNumeric(5) == false;
verifique o conjunto de testes de unidade que eu postei; essa função é o número16
no conjunto de testes. stackoverflow.com/questions/18082/…Desta forma, parece funcionar bem:
Em uma linha:
E para testá-lo:
Peguei emprestado esse regex em http://www.codetoad.com/javascript/isnumeric.asp . Explicação:
fonte
Yahoo! A interface do usuário usa isso:
fonte
new Number(1)
.Isso funciona para números do tipo 0x23 também.
fonte
IsNumeric('')
,IsNumeric(' ')
,IsNumeric(true)
,IsNumeric(false)
,IsNumeric(null)
Voltartrue
em vez defalse
.A resposta aceita falhou no teste nº 7 e acho que é porque você mudou de idéia. Portanto, esta é uma resposta à resposta aceita, com a qual tive problemas.
Durante alguns projetos, eu precisei validar alguns dados e ter a maior certeza possível de que é um valor numérico javascript que pode ser usado em operações matemáticas.
O jQuery e algumas outras bibliotecas javascript já incluem essa função, geralmente chamada
isNumeric
. Há também uma postagem no stackoverflow que foi amplamente aceita como resposta, a mesma rotina geral que as bibliotecas mencionadas anteriormente estão usando.Primeiro, o código acima retornaria true se o argumento fosse uma matriz de comprimento 1 e esse elemento único fosse de um tipo considerado como numérico pela lógica acima. Na minha opinião, se é uma matriz, então não é numérico.
Para aliviar esse problema, adicionei um cheque para descontar matrizes da lógica
Obviamente, você também pode usar
Array.isArray
jquery$.isArray
ou prototype emObject.isArray
vez deObject.prototype.toString.call(n) !== '[object Array]'
Meu segundo problema foi que seqüências literais inteiras hexadecimais negativas ("-0xA" -> -10) não estavam sendo contadas como numéricas. No entanto, seqüências literais inteiras hexadecimais positivas ("0xA" -> 10) foram tratadas como numéricas. Eu precisava que ambos fossem numéricos válidos.
Modifiquei a lógica para levar isso em conta.
Se você estiver preocupado com a criação do regex toda vez que a função for chamada, você poderá reescrevê-lo em um fechamento, algo como isto
Depois, peguei CMSs +30 casos de teste e clonei o teste no jsfiddle, adicionei meus casos de teste extras e minha solução descrita acima.
Pode não substituir a resposta amplamente aceita / usada, mas se isso é mais do que você espera como resultado de sua função isNumeric, espero que isso ajude.
Edição: Como apontado por Bergi , existem outros objetos possíveis que podem ser considerados numéricos e seria melhor colocar na lista de permissões do que na lista negra. Com isso em mente, eu acrescentaria aos critérios.
Quero que minha função isNumeric considere apenas números ou seqüências de caracteres
Com isso em mente, seria melhor usar
Teste as soluções
fonte
IsNumeric('99,999') => false
Sim, o built-in
isNaN(object)
será muito mais rápido do que qualquer análise de expressão regular, porque é embutido e compilado, em vez de interpretado rapidamente.Embora os resultados sejam um pouco diferentes do que você está procurando ( experimente ):
fonte
Use a função
isNaN
. Acredito que se você testar,!isNaN(yourstringhere)
ele funciona bem para qualquer uma dessas situações.fonte
Desde o jQuery 1.7, você pode usar
jQuery.isNumeric()
:Observe que, diferentemente do que você disse,
0x89f
é um número válido (hexa)fonte
Isso pode ser feito sem o RegExp como
fonte
Sei que a pergunta original não mencionou o jQuery, mas se você usa o jQuery, pode:
Simples.
https://api.jquery.com/jQuery.isNumeric/ (a partir do jQuery 1.7)
fonte
não funcionou para mim. Quando coloquei em alerta e testei,
input.length
foiundefined
. Eu acho que não há propriedade para verificar o comprimento inteiro. Então o que eu fiz foiFuncionou bem.
fonte
Se não me engano, isso deve corresponder a qualquer valor válido de número JavaScript, excluindo constantes (
Infinity
,NaN
) e os operadores de sinal+
/-
(porque na verdade não fazem parte do número, no que me diz respeito, são operadores separados):Eu precisava disso para um tokenizador, onde enviar o número para JavaScript para avaliação não era uma opção ... Definitivamente, não é a expressão regular mais curta possível, mas acredito que ele captura todas as sutilezas mais delicadas da sintaxe de número do JavaScript.
Os números válidos incluem:
Números inválidos seriam
fonte
O único problema que tive com a resposta do @ CMS é a exclusão de
NaN
e Infinity, que são números úteis para muitas situações. Uma maneira de verificar se háNaN
valores numéricos que não se igualam a elesNaN != NaN
! Então, existem realmente três testes com os quais você gostaria de lidar ...Meu isComparableNumber está bem próximo de outra resposta elegante , mas lida com representações hexadecimais e outras strings de números.
fonte
Para mim, esta é a melhor maneira:
fonte
Eu gostaria de adicionar o seguinte:
Os números hexadecimais positivos começam com
0x
e os números hexadecimais negativos começam com-0x
. Os números de outubro positivos começam com0
e os números de outubro negativos começam com-0
. Este leva a maior parte do que já foi mencionado em consideração, mas inclui números hexadecimais e octais, negativo científico, Infinito e removeu decimal científico (4e3.2
não é válido).fonte
Eu acho que a função parseFloat pode fazer todo o trabalho aqui. A função abaixo passa em todos os testes desta página, incluindo
isNumeric(Infinity) == true
:fonte
IsNumeric([3]) == true;
IsNumeric([]) == false;
IsNumeric([3, 4]) == false;
mas imagino que seja uma questão de gosto!Alguns testes a serem adicionados:
Eu vim com isso:
A solução abrange:
fonte
Um valor inteiro pode ser verificado por:
Desta forma, é mais fácil e rápido! Todos os testes são verificados!
fonte
Aqui está uma pequena versão melhorada (provavelmente a maneira mais rápida), que eu uso em vez da variante exata do jQuery, eu realmente não sei por que eles não usam esta:
A desvantagem da versão do jQuery é que, se você passar uma string com números iniciais e letras finais, como
"123abc"
oparseFloat | parseInt
extrairá a fração numérica e retornará 123, MAS, o segundo guardaisFinite
falhará de qualquer maneira. Com o+
operador unário , ele morrerá na primeira guarda, já que o + lança NaN para esses híbridos :) Um pouco de desempenho ainda acho que um sólido ganho semântico.fonte
Minha solução
Parece funcionar em todas as situações, mas posso estar errado.
fonte
?
para{0,1}
e\d
para[0-9]
. Além disso,+
e depois envolvê-lo(?:){0,1}
, você também pode usar*
e esquecer os grupos (não) de captura.Estou usando uma solução mais simples:
fonte
Isso deve funcionar. Algumas das funções fornecidas aqui são falhas, também devem ser mais rápidas do que qualquer outra função aqui.
Explicado:
Crie uma cópia de si mesmo, depois converta o número em float e, em seguida, compare-se com o número original, se ainda for um número (inteiro ou flutuante) e corresponda ao número original, ou seja, é realmente um número.
Funciona com seqüências numéricas e números simples. Não funciona com números hexadecimais.
Aviso: use por sua conta e risco, sem garantias.
fonte
Nenhuma das respostas retorna
false
para cadeias vazias, uma correção para isso ...fonte
Para verificar se uma variável contém um número válido e não apenas uma String que se parece com um número,
Number.isFinite(value)
pode ser usada.Isso faz parte do idioma desde o ES2015
Exemplos:
fonte
Number.isFinite('0') -> false
Se n for numérico
Number(n)
, retornará o valor numérico etoString()
retornará para uma sequência. Mas se n não for numéricoNumber(n)
, retornaráNaN
para que não corresponda ao originaln
fonte
Sei que isso já foi respondido muitas vezes, mas a seguir é um candidato decente que pode ser útil em alguns cenários.
Note-se que assume que '.42' NÃO é um número e '4'. NÃO é um número, portanto, isso deve ser levado em consideração.
O
isDecimal
passa no seguinte teste:A idéia aqui é que todo número ou número inteiro tenha uma representação de string "canônica" e toda representação não-canônica deve ser rejeitada. Então, convertemos para um número e retornamos e vemos se o resultado é a sequência original.
Se essas funções são úteis para você depende do caso de uso. Uma característica é que cadeias distintas representam números distintos (se ambas passarem no
isNumber()
teste).Isso é relevante, por exemplo, para números como nomes de propriedades de objetos.
fonte
funções de validação da biblioteca Inbuild do knockoutJs
Estendendo-o, o campo é validado
1) número
self.number = ko.observable(numberValue)
.extend ({number: true}) ;Caso de teste
2) dígito
self.number = ko.observable(numberValue)
.extend ({dígito: verdadeiro}) ;Caso de teste
3) min e max
self.number = ko.observable(numberValue)
.extend ({min: 5}). extend ({max: 10}) ;Este campo aceita valores entre 5 e 10 apenas
Caso de teste
fonte
Se você precisar validar um conjunto especial de decimais y, poderá usar este javascript simples:
http://codesheet.org/codesheet/x1kI7hAD
O Javascript:
fonte
isNumeric=(el)=>{return Boolean(parseFloat(el)) && isFinite(el)}
Nada muito diferente, mas podemos usar o construtor booleano
fonte