2009-07-22 7 views
8

Estoy buscando un método que devuelva un booleano si la cadena que se pasa es un número válido (por ejemplo, "123.55e-9", "-333.556 "). Me No quieren simplemente hacer:Biblioteca de Java para comprobar si una cadena contiene un número * sin * excepciones

public boolean isANumber(String s) { 
    try { 
     BigDecimal a = new BigDecimal(s); 
     return true; 
    } catch (NumberFormatException e) { 
     return false; 
    } 
} 

Claramente, la función debe utilizar una máquina de estados (DFA) para analizar la cadena para hacer ejemplos válidos seguro que no engañan a ella (por ejemplo, "-21, 22.22.2 "," 33-2 "). ¿Sabes si existe una biblioteca de este tipo? Realmente no quiero escribirlo porque es un problema tan obvio que estoy seguro de que volvería a inventar la rueda.

Gracias,

Nick

+0

Por qué es exactamente lo que no desea usar el análisis de BigDecimal? Es la forma más fácil, realmente. – Jorn

+0

Me gustaría saber por qué no quieres usar el fragmento que diste? Si necesita _use_ el número, debe analizarlo? ¿Es solo para validar que una cadena puede ir al back-end como está? –

+0

Porque las excepciones no son menciones para este caso. Las excepciones son, bueno, para excepciones, no para el control del programa. – Malax

Respuesta

6

I evitaría reinventar este método e ir con Apache Commons. Si usas Spring, Struts o muchas otras bibliotecas Java de uso común, a menudo tienen Apache commons incluidos. Querrá el archivo commons-lang.jar. Aquí está el método en el que usted quiere NumberUtils:

isNumber[1] 

public static boolean isNumber(java.lang.String str) 
Checks whether the String a valid Java number. 

Valid numbers include hexadecimal marked with the 0x qualifier, scientific notation and numbers marked with a type qualifier (e.g. 123L). 

Null and empty String will return false. 

Parameters: 
str - the String to check 
Returns: 
true if the string is a correctly formatted number 
3

utilizar un regexp

+0

exactamente. y aquí http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#BigDecimal(java.lang.String) tienes algo de comida para tus pruebas unitarias. – flybywire

+0

+1 desde Commons-Lang no ofrece este – skaffman

+0

Gracias por señalarme en commons-lang. ¡cosas ordenadas! – Malax

2

Sí una expresión regular debe hacer el truco. Solo conozco .Net regexp, pero todos los idiomas regex son bastante similares, así que esto debería comenzar. No lo probé, por lo que es posible que desee probarlo un poco con la clase de expresiones regulares de Java.

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

Algunos de la sintaxis de control de expresión regular:
? - Elemento opcional
| - O operador. Básicamente, permití números con o sin comas si estaban formateados correctamente.
[] - Conjunto de caracteres permitidos
{,} - máximo y mínimo de elemento
* - Cualquier número de elementos, 0 a infinito
+ - Al menos un elemento, 1 a infinito
\ - Carácter de escape
. - Cualquier carácter (De ahí por qué se escapó)

+0

+1 para la implementación real – dfa

+0

actualmente esta expresión coincidirá con 22,22,2.14123415e1 – Salandur

+0

Y no coincidirá con 1e-1. – Bombe

2

Aquí es una función de utilidad basada expresión regular que trabaja muy bien (no cabe en la "" cheque en la expresión regular mientras se mantiene legible):

public class TestRegexp { 
    static final String NUM_REGEX= 
     "-?((([0-9]{1,3})(,[0-9]{3})*)|[0-9]*)(\\.[0-9]+)?([Ee][0-9]*)?"; 
    public static boolean isNum(String s) { 
      return s!=null && s.length()>0 && s.matches(NUM_REGEX); 
    } 
    public static void main(String[]args) { 
     String[] values={ 
       "", 
       "0", 
       "0.1", 
       ".1", 
       "-.5E5", 
       "-12,524.5E5", 
       "-452,456,456,466.5E5", 
       "-452,456,456,466E5", 
       "22,22,2.14123415e1", 
     }; 
     for (String value : values) { 
      System.out.println(value+" is a number: " 
      +isNum(value)); 
     } 
    } 

} 
2

La expresión regular exacta se especifica en el Javadocs para Double.valueOf(String).

Para evitar llamar a este método en una cadena no válida y tener un NumberFormatException ser lanzado, la expresión regular a continuación se puede utilizar para detectar la cadena de entrada:

final String Digits  = "(\\p{Digit}+)"; 
final String HexDigits = "(\\p{XDigit}+)"; 
// an exponent is 'e' or 'E' followed by an optionally 
// signed decimal integer. 
final String Exp  = "[eE][+-]?"+Digits; 
final String fpRegex = 
     ("[\\x00-\\x20]*"+ // Optional leading "whitespace" 
     "[+-]?(" + // Optional sign character 
     "NaN|" +   // "NaN" string 
     "Infinity|" +  // "Infinity" string 

     // A decimal floating-point string representing a finite positive 
     // number without a leading sign has at most five basic pieces: 
     // Digits . Digits ExponentPart FloatTypeSuffix 
     // 
     // Since this method allows integer-only strings as input 
     // in addition to strings of floating-point literals, the 
     // two sub-patterns below are simplifications of the grammar 
     // productions from the Java Language Specification, 2nd 
     // edition, section 3.10.2. 

     // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt 
     "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ 

     // . Digits ExponentPart_opt FloatTypeSuffix_opt 
     "(\\.("+Digits+")("+Exp+")?)|"+ 

     // Hexadecimal strings 
     "((" + 
     // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt 
     "(0[xX]" + HexDigits + "(\\.)?)|" + 

     // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt 
     "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + 

     ")[pP][+-]?" + Digits + "))" + 
     "[fFdD]?))" + 
     "[\\x00-\\x20]*"); // Optional trailing "whitespace" 

if (Pattern.matches(fpRegex, myString)) 
    Double.valueOf(myString); // Will not throw NumberFormatException 
else { 
    // Perform suitable alternative action 
} 
Cuestiones relacionadas