2012-06-28 22 views
5

Sé que puedo hacer coincidir números con Pattern.compile("\\d*");¿Cómo hacer coincidir un largo con expresiones regulares de Java?

Pero no maneja los valores máximos/mínimos largos.

Para problemas de rendimiento relacionados con excepciones, no quiero intentar analizar el largo a menos que realmente sea un largo.

if (LONG_PATTERN.matcher(timestampStr).matches()) { 
    long timeStamp = Long.parseLong(timestampStr); 
    return new Date(timeStamp); 
} else { 
    LOGGER.error("Can't convert " + timestampStr + " to a Date because it is not a timestamp! -> "); 
    return null; 
} 

quiero decir que no quiero ningún bloque try/catch y no me quiero conseguir excepciones planteadas desde hace mucho como "564654954654464654654567879865132154778", que se encuentra fuera del tamaño de una normal Java larga.

¿Alguien tiene un patrón para manejar este tipo de necesidad para los tipos primitivos de Java? ¿El JDK proporciona algo para manejarlo automáticamente? ¿Hay un mecanismo de análisis de fallas en Java?

Gracias


Editar: favor suponer que la "mala cadena larga" no es un caso excepcional. No estoy pidiendo un punto de referencia, estoy aquí para una expresión regular que representa una larga y nada más. Soy consciente del tiempo adicional requerido por la comprobación de expresiones regulares, pero al menos mi análisis largo siempre será constante y nunca dependerá del% de "cadenas largas incorrectas"

No puedo encontrar el enlace de nuevo pero hay un buen benchmark de análisis en StackOverflow que muestra claramente que reutilizar la expresión regular compilada es la más rápida, mucho más rápida que lanzar una excepción, por lo tanto, solo un pequeño umbral de excepciones haría que el sistema fuera más lento que con la verificación adicional de expresiones regulares.

+4

Tenga en cuenta que '" \\ d * "' también coincide con las cadenas vacías. –

+0

Posiblemente [su pregunta ya ha sido solicitada] (http://stackoverflow.com/questions/2563608/check-whether-a-string-is-parsable-into-long-without-try-catch). En mi opinión, las excepciones serán más rápidas que las expresiones regulares. – Sorrow

+0

@Sorrow: Buena captura en la pregunta anterior. Re excepciones vs. expresiones regulares: ¿Qué te hace pensar eso? Lanzar excepciones no es un proceso rápido. Una vez compiladas, las expresiones regulares son bastante rápidas. –

Respuesta

10

El avlue mínimo de un long es -9,223,372,036,854,775,808, y el valor máximo es 9,223,372,036,854,775,807. Entonces, un máximo de 19 dígitos. Por lo tanto, \d{1,19} debe llevarlo allí, quizás con un - opcional, y con ^ y $ para que coincida con los extremos de la cadena.

Así que más o menos :

Pattern LONG_PATTERN = Pattern.compile("^-?\\d{1,19}$"); 

... o algo por el estilo, y suponiendo que no permite que comas (o ya los han eliminado).

Como se señala en los comentarios, lo anterior permite un rango pequeño (en comparación) de valores no válidos, como 9,999,999,999,999,999,999. Puede volverse más complejo con su expresión regular, o simplemente aceptar que lo anterior eliminará la gran mayoría de los números no válidos y, por lo tanto, reducirá el número de excepciones de análisis que obtiene.

+0

no es cierto, su patrón permite el número 9.999.999.999.999.999.999, que NO está en el rango largo – gexicide

+1

@gexicida: Es cierto que puede ser necesaria cierta afinación. Reduciría al menos enormemente * el número de excepciones. –

+0

por supuesto, pero supongo que OP quiere una solución correcta. Pero estoy de acuerdo, el patrón ya filtra la mayoría de los casos malos. – gexicide

1

Simplemente atrapa la NumberFormatException, a menos que este caso ocurra muy a menudo.

Otra forma sería utilizar un patrón que solo permite literales largos. Tal patrón puede ser bastante complejo.

Una tercera forma sería analizar primero el número como BigInt. Luego puede compararlo con Long.MAX_VALUE y Long.MIN_VALUE para verificar si está dentro de los límites de long. Sin embargo, esto podría ser costoso también.

También tenga en cuenta: Analizar el tiempo es bastante rápido, es un método muy optimizado (que, por ejemplo, intenta analizar dos dígitos en un paso). Aplicar la coincidencia de patrones puede ser incluso más costoso que realizar el análisis sintáctico. Lo único lento del análisis es arrojar la NumberFormatException. Por lo tanto, sólo tiene que agarrar la excepción es el mejor camino a seguir si el caso excepcional no sucede muy a menudo

+0

El OP dijo: * "Para problemas de rendimiento relacionados con excepciones no quiero intentar analizar el largo a menos que sea realmente un largo" * –

+0

y luego considerar los otros párrafos de mi respuesta editada :) – gexicide

+0

la idea es conseguir un tiempo de ejecución constante para el método en lugar de un tiempo de ejecución relacionado con la presencia de valores largos erróneos. Por lo que yo sé, he leído un punto de referencia en SO y expresiones regulares, cuando no se recompila cada vez, son bastante rápidos –

1

Esta expresión regular debería hacer lo que necesita:

^(-9223372036854775808|0)$|^((-?)((?!0)\d{1,18}|[1-8]\d{18}|9[0-1]\d{17}|92[0-1]\d{16}|922[0-2]\d{15}|9223[0-2]\d{14}|92233[0-6]\d{13}|922337[0-1]\d{12}|92233720[0-2]\d{10}|922337203[0-5]\d{9}|9223372036[0-7]\d{8}|92233720368[0-4]\d{7}|922337203685[0-3]\d{6}|9223372036854[0-6]\d{5}|92233720368547[0-6]\d{4}|922337203685477[0-4]\d{3}|9223372036854775[0-7]\d{2}|922337203685477580[0-7]))$

Pero esta expresión regular no valida símbolos adicionales como +, L, _ y etc, y si es necesario para validar todos los posibles valores de largo necesitas actualizar esta expresión regular.

Cuestiones relacionadas