2012-06-28 22 views
5

So che posso abbinare i numeri con Pattern.compile("\\d*");Come abbinare un lungo con regex Java?

Ma non gestisce i valori lunghi min/max.

Per problemi di esecuzione relativi alle eccezioni, non voglio provare a analizzare il lungo, a meno che non sia davvero lungo.

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; 
} 

Voglio dire che non voglio alcun blocco try/catch e io non voglio arrivare eccezioni sollevate a lungo come "564654954654464654654567879865132154778", che è fuori dalla dimensione di un Java regolare lungo.

Qualcuno ha un modello per gestire questo tipo di necessità per i tipi di java primitivi? Il JDK fornisce qualcosa per gestirlo automaticamente? Esiste un meccanismo di parsing sicuro in Java?

Grazie


Edit: Si prega di supporre che la "lunga stringa cattivo" non è un caso straordinariamente disponibile. Non sto chiedendo un punto di riferimento, sono qui per una regex che rappresenta un lungo e niente di più. Sono consapevole del tempo aggiuntivo richiesto dal controllo regex, ma almeno il mio lungo parsing sarà sempre costante e non dipenderà mai dalla% di "stringhe lunghe errate"

Non riesco a trovare di nuovo il collegamento ma c'è un buon benchmark di parsing su StackOverflow che mostra chiaramente che riutilizzare la regex compilata con sams è molto veloce, molto più veloce dell'eccezione, quindi solo una piccola soglia di eccezioni renderebbe il sistema più lento rispetto al controllo regex aggiuntivo.

+4

Si noti che '" \\ d * "' corrisponde anche alle stringhe vuote. –

+0

Forse [la tua domanda è già stata posta] (http://stackoverflow.com/questions/2563608/check-whether-a-string-is-parsable-into-long-without-try-catch). A mio parere, le eccezioni saranno più veloci delle espressioni regolari. – Sorrow

+0

@Sorrow: buona presa sulla domanda precedente. Re eccezioni rispetto alle espressioni regolari: cosa ti fa pensare? Le eccezioni di lancio non sono un processo rapido. Una volta compilate, le espressioni regolari sono piuttosto veloci. –

risposta

10

L'avlue minimo di un long è -9,223,372,036,854,775,808, e il valore massimo è 9,223,372,036,854,775,807. Quindi, un massimo di 19 cifre. Quindi, \d{1,19} dovrebbe portarti lì, magari con un - opzionale e con ^ e $ per abbinare le estremità della stringa.

Così circa:

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

... o qualcosa del genere, e supponendo che non si consente virgole (o le hanno già rimosso).

Come indica il gexicide nei commenti, il precedente consente un intervallo piccolo (in confronto) di valori non validi, come ad esempio 9,999,999,999,999,999,999. Puoi diventare più complesso con la tua espressione regolare, o semplicemente accettare che quanto sopra elencherà la stragrande maggioranza dei numeri non validi e quindi riduci il numero di eccezioni di analisi ottenute.

+0

non è vero, il tuo modello consente il numero 9,999,999,999,999,999,999 che NON è nel lungo raggio – gexicide

+1

@gexicide: true, potrebbe essere necessario un po 'di tuning. Ridurrebbe * almeno * il numero di eccezioni. –

+0

ovviamente, ma suppongo che OP voglia una soluzione corretta. Ma sono d'accordo, lo schema filtra già i casi più gravi. – gexicide

1

Acquisisci semplicemente NumberFormatException, a meno che questo caso non avvenga molto spesso.

Un altro modo sarebbe utilizzare un modello che consente solo valori letterali lunghi. Tale modello potrebbe essere piuttosto complesso.

Un terzo modo sarebbe quello di analizzare prima il numero come BigInt. Quindi puoi confrontarlo con Long.MAX_VALUE e Long.MIN_VALUE per verificare se è compreso tra i limiti di long. Tuttavia, questo potrebbe essere anche costoso.

Nota anche: L'analisi di long è abbastanza veloce, è un metodo ottimizzato (che, ad esempio, tenta di analizzare due cifre in un solo passaggio). L'applicazione della corrispondenza del modello potrebbe essere ancora più costosa rispetto all'esecuzione dell'analisi. L'unica cosa che è lenta nell'analisi è lanciare NumberFormatException. Così, semplicemente cattura l'eccezione è il modo migliore per andare se il caso eccezionale non accade troppo spesso

+0

L'OP ha detto: * "Per i problemi di rendimento relativi alle eccezioni, non voglio provare ad analizzare il lungo a meno che non sia davvero lungo" * –

+0

quindi considerare gli altri paragrafi della mia risposta modificata :) – gexicide

+0

l'idea è di ottenere un tempo di esecuzione costante per il metodo anziché un tempo di esecuzione correlato alla presenza di valori lunghi errati. Per quanto ne so, ho letto un benchmark su SO e regex, quando non ricompilato ogni volta, sono piuttosto veloci –

1

Questa espressione regolare dovrebbe fare quello che ti serve:

^(-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]))$

Ma questa espressione regolare non convalida simboli aggiuntivi come +, L, _ ed ecc E se hai bisogno di convalidare tutti i possibili valori Long è necessario aggiornare questo regexp.

Problemi correlati