Cum am putea verifica dacă un Șir de caractere a fost un număr înainte de a-l analizez?
Acest lucru se face în general cu o simplă funcție definită de utilizator (de exemplu, Roll-ta-proprii "isNumeric" funcția).
Ceva de genul:
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
Cu toate acestea, dacă te're de asteptare această funcție o mulțime, și te aștepți ca multe dintre controale pentru a eșua din cauza a nu fi un număr, apoi performanta de acest mecanism nu va fi mare, din moment ce're bazându-se pe excepții fiind aruncat pentru fiecare eșec, care este destul de costisitoare operatiunea.
O abordare alternativă ar fi să folosesc o expresie regulată pentru a verifica validitatea de a fi un număr:
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
Fii atent cu cele de mai sus RegEx mecanism, deși, după cum se va reuși dacă're folosind non-arabă cifre (de exemplu, cifre, altele decât 0 până la 9). Acest lucru este pentru că "\d" parte a RegEx va potrivi numai [0-9] și eficient e't pe plan internațional numeric conștient. (Vă mulțumim pentru OregonGhost pentru a evidenția acest lucru!)
Sau chiar o altă alternativă este de a utiliza Java's built-in java.text.NumberFormat obiect pentru a vedea dacă, după parcurgerea șirului parser este poziția la sfârșitul șirului. Dacă este, putem presupune că întregul șir este numeric:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
Cu Apache Commons Lang 3.5 și mai sus: NumberUtils.isCreatable
sau StringUtils.isNumeric
.
Cu Apache Commons Lang 3.4 și mai jos: NumberUtils.isnum
sau StringUtils.isNumeric
.
Puteți folosi, de asemenea, StringUtils.isNumericSpace
, care returnează "adevărat" pentru siruri de caractere goale și ignoră spații interne în șir. Un alt mod este de a utiliza StringUtils.isParsable
care, practic, verifică numărul este parsable potrivit Java. (Legat javadocs conține exemple detaliate pentru fiecare metodă.)
dacă sunteți pe android, atunci ar trebui să utilizați:
android.text.TextUtils.isDigitsOnly(CharSequence str)
documentație pot fi găsite aici
păstrați-l simplu. cea mai mare parte toata lumea poate "re-program" (același lucru).
Ca @CraigTP a menționat în răspunsul său excelent, am, de asemenea, performanțe similare preocupările privind utilizarea Excepții pentru a testa dacă șirul este numerică sau nu. Așa că am ajunge să împărțim șirul și de a folosi java.lang.Caracter.isDigit()`.
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
Potrivit Javadoc, Caracter.isDigit(char)
va recunoaște corect non-latine cifre. Performanță înțelept, cred că un simplu N numărul de comparații în cazul în care N este numărul de caractere din șirul ar fi de calcul mai eficient decât a face un regex potrivire.
UPDATE: așa Cum sa arătat de către Jean-François Corbett în comentariu, codul de mai sus ar valida numere întregi pozitive, care acoperă majoritatea caz de utilizare. Mai jos este codul actualizat corect validează numere zecimale în funcție de setările regionale implicite utilizate în sistemul dvs., cu presupunerea ca separator zecimal apar doar o dată în șir.
public static boolean isStringNumeric( String str )
{
DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
char localeMinusSign = currentLocaleSymbols.getMinusSign();
if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;
boolean isDecimalSeparatorFound = false;
char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();
for ( char c : str.substring( 1 ).toCharArray() )
{
if ( !Character.isDigit( c ) )
{
if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
{
isDecimalSeparatorFound = true;
continue;
}
return false;
}
}
return true;
}
Java 8 lambda expresii.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Google's Guava biblioteca oferă un frumos helper metodă pentru a face acest lucru: Int.tryParse
. Utilizați-l ca Întreg.parseInt, dar ea se întoarce
null` mai degrabă decât arunca o Excepție dacă șirul nu analizare a valid integer. Rețineți că, se întoarce Întreg, nu int, astfel încât să aveți pentru a converti/autobox înapoi la int.
Exemplu:
String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);
int i1 = -1;
if (oInt1 != null) {
i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
i2 = oInt2.intValue();
}
System.out.println(i1); // prints 22
System.out.println(i2); // prints -1
Cu toate acestea, ca de versiunea curentă -- Guava r11-este încă marcat @Beta.
Nu am't evaluate ea. Se uită la codul sursă nu este ceva deasupra capului dintr-o mulțime de bun-simț de verificare, dar, în final, ei folosesc Caracter.cifre(string.charAt(idx))`, similare, dar ușor diferite de la, răspunsul de la @Ibrahim de mai sus. Nu există nici o excepție de manipulare aeriene sub pătură în punerea lor în aplicare.
Nu utilizați Excepții pentru a valida valorile tale. Utilizarea Util libs în loc ca apache NumberUtils:
NumberUtils.isNumber(myStringValue);
Edit:
Vă rog să observați că, dacă șirul începe cu 0, NumberUtils va interpreta valoarea ta ca hexazecimal.
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
De ce este toată lumea împinge de excepție/regex soluții?
În timp ce înțeleg cei mai mulți oameni sunt în regulă cu ajutorul try/catch, dacă vrei să faci asta frecvent... poate fi extrem de obositor.
Ceea ce am făcut aici a fost să ia regex, la parseNumber() metode și matrice metodă de căutare pentru a vedea care a fost cel mai eficient. De data asta, m-am uitat doar la numere întregi.
public static boolean isNumericRegex(String str) {
if (str == null)
return false;
return str.matches("-?\\d+");
}
public static boolean isNumericArray(String str) {
if (str == null)
return false;
char[] data = str.toCharArray();
if (data.length <= 0)
return false;
int index = 0;
if (data[0] == '-' && data.length > 1)
index = 1;
for (; index < data.length; index++) {
if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
return false;
}
return true;
}
public static boolean isNumericException(String str) {
if (str == null)
return false;
try {
/* int i = */ Integer.parseInt(str);
} catch (NumberFormatException nfe) {
return false;
}
return true;
}
Rezultatele din viteza am primit au fost:
Done with: for (int i = 0; i < 10000000; i++)...
With only valid numbers ("59815833" and "-59815833"):
Array numeric took 395.808192 ms [39.5808192 ns each]
Regex took 2609.262595 ms [260.9262595 ns each]
Exception numeric took 428.050207 ms [42.8050207 ns each]
// Negative sign
Array numeric took 355.788273 ms [35.5788273 ns each]
Regex took 2746.278466 ms [274.6278466 ns each]
Exception numeric took 518.989902 ms [51.8989902 ns each]
// Single value ("1")
Array numeric took 317.861267 ms [31.7861267 ns each]
Regex took 2505.313201 ms [250.5313201 ns each]
Exception numeric took 239.956955 ms [23.9956955 ns each]
// With Character.isDigit()
Array numeric took 400.734616 ms [40.0734616 ns each]
Regex took 2663.052417 ms [266.3052417 ns each]
Exception numeric took 401.235906 ms [40.1235906 ns each]
With invalid characters ("5981a5833" and "a"):
Array numeric took 343.205793 ms [34.3205793 ns each]
Regex took 2608.739933 ms [260.8739933 ns each]
Exception numeric took 7317.201775 ms [731.7201775 ns each]
// With a single character ("a")
Array numeric took 291.695519 ms [29.1695519 ns each]
Regex took 2287.25378 ms [228.725378 ns each]
Exception numeric took 7095.969481 ms [709.5969481 ns each]
With null:
Array numeric took 214.663834 ms [21.4663834 ns each]
Regex took 201.395992 ms [20.1395992 ns each]
Exception numeric took 233.049327 ms [23.3049327 ns each]
Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check
Disclaimer: am'm, nu pretind că aceste metode sunt 100% optimizat, au're doar pentru demonstrație a datelor
Excepții de câștigat dacă și numai dacă numărul este de 4 caractere sau mai puțin, și fiecare șir este întotdeauna un număr... în care caz, de ce trebuie chiar un cec?
Pe scurt, este extrem de dureros, dacă tu a alerga în numere invalide frecvent cu try/catch, ceea ce face sens. O regulă importantă nu urmați întotdeauna este nu utilizați NICIODATĂ try/catch pentru program de curgere. Acesta este un exemplu de ce.
Interesant, simplu, dacă char <0 || >9 a fost extrem de simplu de a scrie, ușor de reținut (și ar trebui să funcționeze în mai multe limbi) și câștigă aproape toate scenariile de testare.
Singurul dezavantaj este că am'm ghicitul număr Întreg.parseInt() s-ar putea ocupa non ASCII numere, întrucât matrice căutarea metodă nu.
Pentru cei întrebam de ce am spus-o's ușor să vă amintiți caracter matrice, dacă știi că nu's nici semne negative, puteți obține cu ușurință departe cu ceva condensat ca aceasta:
public static boolean isNumericArray(String str) {
if (str == null)
return false;
for (char c : str.toCharArray())
if (c < '0' || c > '9')
return false;
return true;
În cele din urmă ca o notă finală, am fost curios despre assigment operator în a acceptat exemplu, cu toate voturile sus. Adăugarea în misiune de
double d = Double.parseDouble(...)
nu este numai inutil, din moment ce tu nu't de a folosi chiar valoarea, dar se irosește timpul de prelucrare și a crescut de execuție de câteva nanosecunde (care a condus la o 100-200 ms creștere în teste). Pot't văd de ce cineva ar face asta, deoarece este de fapt o muncă suplimentară pentru a reduce performanțele.
Te'd cred că ar fi optimizat, deși poate că ar trebui să verificați bytecode și a vedea ce compilator este de a face. Asta nu't explice de ce a arătat întotdeauna cât mai îndelungată, pentru mine, deși, dacă nu cumva este optimizat afară... prin urmare, mă întreb ce's întâmplă. Ca o notă: Prin îndelungate, adică execută testul de 10000000 de iterații, și care rulează programul de mai multe ori (10x+) a arătat întotdeauna să fie mai lent.
EDIT: Actualizat un test de Caracter.isDigit()
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
CraigTP's expresie regulată (arătat mai sus) produce unele rezultate fals pozitive. E. g. "23y4" va fi considerat ca un număr, deoarece '.' se potrivește cu orice caracter nu punctul zecimal.
De asemenea, se va respinge orice număr cu un lider '+'
O alternativă care evită aceste două probleme minore este
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
Putem încerca să înlocuiască toate numerele din șir dat cu ("") ie spațiu gol și dacă lungimea șirului este zero, atunci putem spune că, având în șirul conține numai numere. [Dacă ați găsit acest răspuns util atunci vă rugăm să ia în considerare până de vot it] Exemplu:
boolean isNumber(String str){
if(str.length() == 0)
return false; //To check if string is empty
if(str.charAt(0) == '-')
str = str.replaceFirst("-","");// for handling -ve numbers
System.out.println(str);
str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points
if(str.length() == 0)
return false; // to check if it is empty string after removing -ve sign and decimal point
System.out.println(str);
return str.replaceAll("[0-9]","").length() == 0;
}
Puteți utiliza NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
Aici a fost răspunsul meu la această problemă.
O prinde tot confortul metodă pe care o puteți utiliza pentru a analiza orice Șir cu orice tip de parser: isParsable(Obiect parser, String str)
. Parser-ul poate fi o "Clasa" sau un "obiect". Acest lucru va, de asemenea, vă permite să utilizați personalizat interpretoare te'am scris și ar trebui să lucreze pentru totdeauna scenariu, de exemplu:
isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");
Aici's my codul complet cu metoda descrieri.
import java.lang.reflect.*;
/**
* METHOD: isParsable<p><p>
*
* This method will look through the methods of the specified <code>from</code> parameter
* looking for a public method name starting with "parse" which has only one String
* parameter.<p>
*
* The <code>parser</code> parameter can be a class or an instantiated object, eg:
* <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
* <code>Class</code> type then only static methods are considered.<p>
*
* When looping through potential methods, it first looks at the <code>Class</code> associated
* with the <code>parser</code> parameter, then looks through the methods of the parent's class
* followed by subsequent ancestors, using the first method that matches the criteria specified
* above.<p>
*
* This method will hide any normal parse exceptions, but throws any exceptions due to
* programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
* parameter which has no matching parse methods, a NoSuchMethodException will be thrown
* embedded within a RuntimeException.<p><p>
*
* Example:<br>
* <code>isParsable(Boolean.class, "true");<br>
* isParsable(Integer.class, "11");<br>
* isParsable(Double.class, "11.11");<br>
* Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
* isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
* <p>
*
* @param parser The Class type or instantiated Object to find a parse method in.
* @param str The String you want to parse
*
* @return true if a parse method was found and completed without exception
* @throws java.lang.NoSuchMethodException If no such method is accessible
*/
public static boolean isParsable(Object parser, String str) {
Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
Method[] methods = theClass.getMethods();
// Loop over methods
for (int index = 0; index < methods.length; index++) {
Method method = methods[index];
// If method starts with parse, is public and has one String parameter.
// If the parser parameter was a Class, then also ensure the method is static.
if(method.getName().startsWith("parse") &&
(!staticOnly || Modifier.isStatic(method.getModifiers())) &&
Modifier.isPublic(method.getModifiers()) &&
method.getGenericParameterTypes().length == 1 &&
method.getGenericParameterTypes()[0] == String.class)
{
try {
foundAtLeastOne = true;
method.invoke(parser, str);
return true; // Successfully parsed without exception
} catch (Exception exception) {
// If invoke problem, try a different method
/*if(!(exception instanceof IllegalArgumentException) &&
!(exception instanceof IllegalAccessException) &&
!(exception instanceof InvocationTargetException))
continue; // Look for other parse methods*/
// Parse method refuses to parse, look for another different method
continue; // Look for other parse methods
}
}
}
// No more accessible parse method could be found.
if(foundAtLeastOne) return false;
else throw new RuntimeException(new NoSuchMethodException());
}
/**
* METHOD: willParse<p><p>
*
* A convienence method which calls the isParseable method, but does not throw any exceptions
* which could be thrown through programatic errors.<p>
*
* Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
* errors can be caught in development, unless the value of the <code>parser</code> parameter is
* unpredictable, or normal programtic exceptions should be ignored.<p>
*
* See {@link #isParseable(Object, String) isParseable} for full description of method
* usability.<p>
*
* @param parser The Class type or instantiated Object to find a parse method in.
* @param str The String you want to parse
*
* @return true if a parse method was found and completed without exception
* @see #isParseable(Object, String) for full description of method usability
*/
public static boolean willParse(Object parser, String str) {
try {
return isParsable(parser, str);
} catch(Throwable exception) {
return false;
}
}
Excepții sunt scumpe, dar în acest caz RegEx durează mult mai mult. Codul de mai jos arată un test simplu de două funcții-una folosind excepții și cu regex. Pe masina mea RegEx versiune este de 10 ori mai lent decât o excepție.
import java.util.Date;
public class IsNumeric {
public static boolean isNumericOne(String s) {
return s.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
public static boolean isNumericTwo(String s) {
try {
Double.parseDouble(s);
return true;
} catch (Exception e) {
return false;
}
}
public static void main(String [] args) {
String test = "12345.F";
long before = new Date().getTime();
for(int x=0;x<1000000;++x) {
//isNumericTwo(test);
isNumericOne(test);
}
long after = new Date().getTime();
System.out.println(after-before);
}
}
Regex Potrivire
Aici este un alt exemplu actualizat "CraigTP" regex potrivire cu mai multe validări.
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
Regex Test
1 -- **VALID**
1. -- INVALID
1.. -- INVALID
1.1 -- **VALID**
1.1.1 -- INVALID
-1 -- **VALID**
--1 -- INVALID
-1. -- INVALID
-1.1 -- **VALID**
-1.1.1 -- INVALID
// vă rugăm să verificați de mai jos codul
public static boolean isDigitsOnly(CharSequence str) {
final int len = str.length();
for (int i = 0; i < len; i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
Un bine-efectuarea de abordare a evita try-catch și manipularea numerelor negative și notație științifică.
Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );
public static boolean isNumeric( String value )
{
return value != null && PATTERN.matcher( value ).matches();
}
Aici este meu de clasă pentru a verifica dacă un șir este numeric. Acesta stabilește, de asemenea numerice, siruri de caractere:
Aici te duci...
public class NumUtils {
/**
* Transforms a string to an integer. If no numerical chars returns a String "0".
*
* @param str
* @return retStr
*/
static String makeToInteger(String str) {
String s = str;
double d;
d = Double.parseDouble(makeToDouble(s));
int i = (int) (d + 0.5D);
String retStr = String.valueOf(i);
System.out.printf(retStr + " ");
return retStr;
}
/**
* Transforms a string to an double. If no numerical chars returns a String "0".
*
* @param str
* @return retStr
*/
static String makeToDouble(String str) {
Boolean dotWasFound = false;
String orgStr = str;
String retStr;
int firstDotPos = 0;
Boolean negative = false;
//check if str is null
if(str.length()==0){
str="0";
}
//check if first sign is "-"
if (str.charAt(0) == '-') {
negative = true;
}
//check if str containg any number or else set the string to '0'
if (!str.matches(".*\\d+.*")) {
str = "0";
}
//Replace ',' with '.' (for some european users who use the ',' as decimal separator)
str = str.replaceAll(",", ".");
str = str.replaceAll("[^\\d.]", "");
//Removes the any second dots
for (int i_char = 0; i_char < str.length(); i_char++) {
if (str.charAt(i_char) == '.') {
dotWasFound = true;
firstDotPos = i_char;
break;
}
}
if (dotWasFound) {
String befDot = str.substring(0, firstDotPos + 1);
String aftDot = str.substring(firstDotPos + 1, str.length());
aftDot = aftDot.replaceAll("\\.", "");
str = befDot + aftDot;
}
//Removes zeros from the begining
double uglyMethod = Double.parseDouble(str);
str = String.valueOf(uglyMethod);
//Removes the .0
str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");
retStr = str;
if (negative) {
retStr = "-"+retStr;
}
return retStr;
}
static boolean isNumeric(String str) {
try {
double d = Double.parseDouble(str);
} catch (NumberFormatException nfe) {
return false;
}
return true;
}
}
// only int
public static boolean isNumber(int num)
{
return (num >= 48 && c <= 57); // 0 - 9
}
// is type of number including . - e E
public static boolean isNumber(String s)
{
boolean isNumber = true;
for(int i = 0; i < s.length() && isNumber; i++)
{
char c = s.charAt(i);
isNumber = isNumber & (
(c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
);
}
return isInteger;
}
// is type of number
public static boolean isInteger(String s)
{
boolean isInteger = true;
for(int i = 0; i < s.length() && isInteger; i++)
{
char c = s.charAt(i);
isInteger = isInteger & ((c >= '0' && c <= '9'));
}
return isInteger;
}
public static boolean isNumeric(String s)
{
try
{
Double.parseDouble(s);
return true;
}
catch (Exception e)
{
return false;
}
}