Jak sprawdziłbyś, czy Łańcuch był liczbą przed analizą?
Integer.parseInt()
nie będą w stanie przeanalizować numerów telefonów komórkowych NumberFormatException
.
Jak sprawdziłbyś, czy Łańcuch był liczbą przed analizą?
Integer.parseInt()
nie będą w stanie przeanalizować numerów telefonów komórkowych NumberFormatException
.
Odpowiedzi:
Z Apache Commons Lang 3.5 i nowszym: NumberUtils.isCreatable
lubStringUtils.isNumeric
.
Z Apache Commons Lang 3.4 i niższymi: NumberUtils.isNumber
lub StringUtils.isNumeric
.
Możesz także użyć, StringUtils.isNumericSpace
które zwraca true
puste ciągi i ignoruje wewnętrzne spacje w ciągu. Innym sposobem jest użycie, NumberUtils.isParsable
które zasadniczo sprawdza, czy liczba jest możliwa do parsowania zgodnie z Javą. (Połączone javadocs zawierają szczegółowe przykłady dla każdej metody.)
StringUtils.isNumeric()
prawdopodobnie nie byłoby to właściwe tutaj, ponieważ sprawdza tylko, czy ciąg znaków jest ciągiem cyfr. Byłoby dobrze dla większości liczb całkowitych, ale nie dla liczb z ułamkami dziesiętnymi, separatorów grup itp.
StringUtils
nie obsługuje znaków wiodących, ale powinieneś sprawdzić NumberUtils.isCreatable
, poprawnie obsługuje negatywy.
Zasadniczo odbywa się to za pomocą prostej funkcji zdefiniowanej przez użytkownika (tj. „Włóż własną funkcję„ isNumeric ”).
Coś jak:
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
Jeśli jednak często wywołujesz tę funkcję i oczekujesz, że wiele kontroli zakończy się niepowodzeniem z powodu braku bycia liczbą, to działanie tego mechanizmu nie będzie świetne, ponieważ polegasz na wyjątkach zgłaszanych dla każdej awarii, co jest dość kosztowną operacją.
Alternatywnym podejściem może być użycie wyrażenia regularnego w celu sprawdzenia ważności bycia liczbą:
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
Uważaj jednak na powyższy mechanizm RegEx, ponieważ zawiedzie, jeśli używasz cyfr spoza arabskiego (tj. Cyfr od 0 do 9). Wynika to z faktu, że część „\ d” RegEx będzie pasować tylko do [0-9] i faktycznie nie jest międzynarodowo świadoma liczbowo. (Podziękowania dla OregonGhost za zwrócenie na to uwagi!)
Lub jeszcze inną alternatywą jest użycie wbudowanego obiektu Java java.text.NumberFormat, aby sprawdzić, czy po analizie ciągu pozycja parsera znajduje się na końcu ciągu. Jeśli tak, możemy założyć, że cały ciąg jest liczbowy:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
.
w wyrażeniu regularnym będzie pasować dowolny znak, a nie tylko separator dziesiętny.
jeśli używasz Androida, powinieneś użyć:
android.text.TextUtils.isDigitsOnly(CharSequence str)
dokumentacja znajduje się tutaj
zachowaj prostotę . przeważnie każdy może „przeprogramować” (to samo).
.
,-
Wyrażenia lambda Java 8.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Jak wspomniał @CraigTP w swojej doskonałej odpowiedzi, mam podobne obawy dotyczące wydajności przy użyciu wyjątków w celu sprawdzenia, czy łańcuch jest liczbowy, czy nie. W rezultacie dzielę ciąg i używam java.lang.Character.isDigit()
.
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
Według Javadoc , Character.isDigit(char)
poprawnie rozpoznaje niełacińskie cyfr. Pod względem wydajności myślę, że prosta liczba N porównań, w których N jest liczbą znaków w łańcuchu, byłaby bardziej wydajna obliczeniowo niż dopasowanie wyrażenia regularnego.
AKTUALIZACJA: Jak zauważył Jean-François Corbett w komentarzu, powyższy kod sprawdziłby tylko liczby całkowite dodatnie, co obejmuje większość mojego przypadku użycia. Poniżej znajduje się zaktualizowany kod, który poprawnie sprawdza poprawność liczb dziesiętnych zgodnie z domyślnymi ustawieniami narodowymi używanymi w systemie, przy założeniu, że separator dziesiętny występuje tylko raz w ciągu.
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;
}
toCharArray()
spowoduje utworzenie kopii tablicy w obiekcie String, ponieważ ciągi są niezmienne. Prawdopodobnie szybciej użyć charAt(int index)
metody bezpośrednio na obiekcie String.
StringIndexOutOfBoundsException
kiedy przeszedł ciąg o długości 0. Może być zamocowaneif(str.length() == 0) return false;
Biblioteka Guava Google zapewnia miły metody pomocnika, aby to zrobić: Ints.tryParse
. Używasz go w ten sposób, Integer.parseInt
ale zwraca on null
zamiast rzucać wyjątek, jeśli ciąg nie parsuje prawidłowej liczby całkowitej. Zauważ, że zwraca Integer, a nie int, więc musisz przekonwertować / autobox z powrotem na int.
Przykład:
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
Jednak od obecnego wydania - Guava r11 - nadal jest oznaczony @Beta.
Nie porównałem tego. Patrząc na kod źródłowy, pojawia się pewien narzut związany z dużą ilością sprawdzania poprawności, ale w końcu używają Character.digit(string.charAt(idx))
podobnej, ale nieco innej niż odpowiedź z @Ibrahim powyżej. W ich implementacji nie ma wyjątku obsługa kosztów ogólnych pod przykryciem.
Nie używaj wyjątków do sprawdzania poprawności swoich wartości. Zamiast tego użyj Util libs jak apache NumberUtils:
NumberUtils.isNumber(myStringValue);
Edytuj :
Zauważ, że jeśli łańcuch zaczyna się od 0, NumberUtils zinterpretuje twoją wartość jako szesnastkową.
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Number.isNumber()
.
Number.isNumber()
była obecna od pierwszej wersji odpowiedzi, datowanej na 24 września 12 o 17:01.
Dlaczego wszyscy naciskają na rozwiązania wyjątkowe / wyrażenia regularne?
Chociaż rozumiem, że większość ludzi nie ma nic przeciwko używaniu try / catch, jeśli chcesz to robić często ... może to być bardzo obciążające.
To, co zrobiłem tutaj, to wzięcie wyrażenia regularnego, metod parseNumber () i metody przeszukiwania tablicy, aby sprawdzić, która z nich była najbardziej wydajna. Tym razem spojrzałem tylko na liczby całkowite.
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;
}
Wyniki, które uzyskałem, były następujące:
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
Oświadczenie: Nie twierdzę, że te metody są w 100% zoptymalizowane, służą jedynie do demonstracji danych
Wyjątki wygrane wtedy i tylko wtedy, gdy liczba ma 4 znaki lub mniej, a każdy ciąg jest zawsze liczbą ... w takim przypadku, po co w ogóle mieć czek?
Krótko mówiąc, jest to bardzo bolesne, jeśli często próbujesz złapać nieprawidłowe liczby za pomocą try / catch, co ma sens. Ważną zasadą, której zawsze przestrzegam jest NIGDY nie używaj try / catch do przebiegu programu . To jest przykład dlaczego.
Co ciekawe, prosty jeśli char <0 || > 9 było niezwykle łatwe do napisania, łatwe do zapamiętania (i powinno działać w wielu językach) i wygrywa prawie wszystkie scenariusze testowe.
Jedynym minusem jest to, że zgaduję, że Integer.parseInt () może obsługiwać liczby inne niż ASCII, podczas gdy metoda wyszukiwania tablicowego nie.
Dla tych, którzy zastanawiają się, dlaczego powiedziałem, że łatwo jest zapamiętać tablicę znaków, jeśli wiesz, że nie ma żadnych negatywnych znaków, możesz łatwo uciec od czegoś skondensowanego:
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;
Wreszcie, jako ostatnia uwaga, byłem ciekawy operatora przypisania w przyjętym przykładzie z wszystkimi głosami. Dodanie w przypisaniu
double d = Double.parseDouble(...)
jest nie tylko bezużyteczny, ponieważ nawet nie używasz tej wartości, ale marnuje czas przetwarzania i wydłuża czas działania o kilka nanosekund (co doprowadziło do wzrostu testów o 100-200 ms). Nie rozumiem, dlaczego ktoś miałby to zrobić, ponieważ w rzeczywistości jest to dodatkowa praca w celu zmniejszenia wydajności.
Można by pomyśleć, że zostałby zoptymalizowany ... chociaż może powinienem sprawdzić kod bajtowy i zobaczyć, co robi kompilator. To nie tłumaczy, dlaczego zawsze wydawało mi się, że jest dłuższe, jeśli jest w jakiś sposób zoptymalizowane ... dlatego zastanawiam się, co się dzieje. Uwaga: przez dłuższy czas mam na myśli uruchomienie testu dla iteracji 10000000, a wielokrotne uruchomienie tego programu (10x +) zawsze pokazało, że jest wolniejszy.
EDYCJA: Zaktualizowano test dla Character.isDigit ()
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
Wyrażenie regularne CraigTP (pokazane powyżej) powoduje pewne fałszywe alarmy. Np. „23y4” będzie liczone jako liczba, ponieważ „.” dopasowuje dowolny znak inny niż przecinek dziesiętny.
Odrzuci także dowolną liczbę z wiodącym „+”
Alternatywą, która pozwala uniknąć tych dwóch drobnych problemów, jest
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
true
pojedynczy plus "+"
lub minus "-"
, a false
dla"0."
matches("-?\\d+([.]\\d+)?")
Możemy spróbować zastąpić wszystkie liczby z podanego ciągu ciągiem („”), tj. Spacją, a jeśli po tym czasie długość łańcucha wyniesie zero, możemy powiedzieć, że podany ciąg zawiera tylko liczby. [Jeśli uznasz, że ta odpowiedź była pomocna, zastanów się nad jej głosowaniem] Przykład:
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;
}
""
jest wiele, ale "3.14"
i "-1"
nie są?
Możesz użyć NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
value
.
Jeśli używasz Java do tworzenia aplikacji na Androida, możesz użyć funkcji TextUtils.isDigitsOnly .
Oto moja odpowiedź na problem.
Łapacz wszystkim metoda wygoda, które można wykorzystać do analizowania dowolny ciąg z dowolnym typem parsera: isParsable(Object parser, String str)
. Analizator składni może być a Class
lub an object
. Umożliwi to również użycie napisanych przez Ciebie niestandardowych parserów i powinno działać na zawsze, np .:
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");
Oto mój kod wraz z opisami metod.
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;
}
}
Aby dopasować tylko dodatnie liczby całkowite dziesięciu, które zawierają tylko cyfry ASCII, użyj:
public static boolean isNumeric(String maybeNumeric) {
return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
Skuteczne podejście pozwalające uniknąć prób połowu i obsługi liczb ujemnych i notacji naukowej.
Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );
public static boolean isNumeric( String value )
{
return value != null && PATTERN.matcher( value ).matches();
}
Oto moja klasa do sprawdzania, czy łańcuch jest liczbowy. Naprawia również ciągi liczbowe:
Proszę bardzo...
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;
}
}
Dopasowywanie wyrażeń regularnych
Oto kolejny przykład ulepszonego dopasowania wyrażenia regularnego „CraigTP” z większą liczbą sprawdzeń poprawności.
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
Test Regex
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
Wyjątki są drogie, ale w tym przypadku RegEx trwa znacznie dłużej. Poniższy kod pokazuje prosty test dwóch funkcji - jednej z wyjątkami i drugiej z wyrażeniem regularnym. Na moim komputerze wersja RegEx jest 10 razy wolniejsza niż wyjątek.
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);
}
}
// sprawdź poniższy kod
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;
}
// 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;
}
}
To prosty przykład tego sprawdzenia:
public static boolean isNumericString(String input) {
boolean result = false;
if(input != null && input.length() > 0) {
char[] charArray = input.toCharArray();
for(char c : charArray) {
if(c >= '0' && c <= '9') {
// it is a digit
result = true;
} else {
result = false;
break;
}
}
}
return result;
}
Możesz użyć obiektu java.util.Scanner.
public static boolean isNumeric(String inputData) {
Scanner sc = new Scanner(inputData);
return sc.hasNextInt();
}
Zmodyfikowałem rozwiązanie CraigTP, aby akceptować notację naukową oraz kropkę i przecinek jako separatory dziesiętne
^-?\d+([,\.]\d+)?([eE]-?\d+)?$
przykład
var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false
Dlatego podoba mi się podejście Try * w .NET. Oprócz tradycyjnej metody analizy składni, która jest podobna do metody Java, dostępna jest również metoda TryParse. Nie jestem dobry w składni Java (parametry wyjściowe?), Dlatego proszę traktować poniższe elementy jako pseudo-kod. Powinno to jednak wyjaśnić tę koncepcję.
boolean parseInteger(String s, out int number)
{
try {
number = Integer.parseInt(myString);
return true;
} catch(NumberFormatException e) {
return false;
}
}
Stosowanie:
int num;
if (parseInteger("23", out num)) {
// Do something with num.
}
Parsuj (tj. Za pomocą Integer#parseInt
) i po prostu złap wyjątek. =)
Aby wyjaśnić: funkcja parseInt sprawdza, czy może parsować liczbę w każdym przypadku (oczywiście), a jeśli i tak chcesz ją przeanalizować, nie będziesz miał żadnego wpływu na wydajność poprzez wykonanie parsowania.
Jeśli nie chcesz go analizować (lub analizować bardzo, bardzo rzadko), możesz oczywiście zrobić to inaczej.
Możesz użyć NumberUtils.isCreatable () z Apache Commons Lang .
Ponieważ NumberUtils.isNumber będzie przestarzałe w 4.0, więc użyj NumberUtils.isCreatable ().
Java 8 Stream, wyrażenie lambda, interfejs funkcjonalny
Wszystkie obsługiwane sprawy ( ciąg pusty, ciąg pusty itp. )
String someString = null; // something="", something="123abc", something="123123"
boolean isNumeric = Stream.of(someString)
.filter(s -> s != null && !s.isEmpty())
.filter(Pattern.compile("\\D").asPredicate().negate())
.mapToLong(Long::valueOf)
.boxed()
.findAny()
.isPresent();
Zilustrowałem niektóre warunki sprawdzania liczb i miejsc po przecinku bez użycia interfejsu API,
Sprawdź Fix Długość 1 cyfra
Character.isDigit(char)
Sprawdź numer stałej długości (zakładając, że długość wynosi 6)
String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");
Sprawdź liczbę różnych długości między (Załóżmy, że długość 4 do 6)
// {n,m} n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");
String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");
Sprawdź liczbę dziesiętną o zmiennej długości między (Załóżmy, że długość od 4 do 7)
// It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");
String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");
String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");
String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");
String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");
String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");
String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");
Mam nadzieję, że pomoże to komuś.
Opierając się na innych odpowiedziach, napisałem własną i nie używa wzorców ani parsowania ze sprawdzaniem wyjątków.
Sprawdza maksymalnie jeden znak minus i sprawdza maksymalnie jeden przecinek dziesiętny.
Oto kilka przykładów i ich wyników:
„1”, „-1”, „-1.5” i „-1.556” zwracają wartość true
„1..5”, „1A.5”, „1.5D”, „-” i „--1” zwracają wartość false
Uwaga: W razie potrzeby możesz zmodyfikować ten parametr, aby zaakceptować parametr Locale i przekazać go do wywołań DecimalFormatSymbols.getInstance () w celu użycia określonego ustawienia regionalnego zamiast bieżącego.
public static boolean isNumeric(final String input) {
//Check for null or blank string
if(input == null || input.isBlank()) return false;
//Retrieve the minus sign and decimal separator characters from the current Locale
final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
//Check if first character is a minus sign
final var isNegative = input.charAt(0) == localeMinusSign;
//Check if string is not just a minus sign
if (isNegative && input.length() == 1) return false;
var isDecimalSeparatorFound = false;
//If the string has a minus sign ignore the first character
final var startCharIndex = isNegative ? 1 : 0;
//Check if each character is a number or a decimal separator
//and make sure string only has a maximum of one decimal separator
for (var i = startCharIndex; i < input.length(); i++) {
if(!Character.isDigit(input.charAt(i))) {
if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
isDecimalSeparatorFound = true;
} else return false;
}
}
return true;
}
Oto dwie metody, które mogą działać. (Bez użycia wyjątków). Uwaga: Java jest domyślnie wartością przekazywaną, a wartością ciągu jest adres danych obiektowych ciągu. Więc kiedy to robisz
stringNumber = stringNumber.replaceAll(" ", "");
Zmieniłeś wartość wejściową, tak aby nie miała spacji. Możesz usunąć tę linię, jeśli chcesz.
private boolean isValidStringNumber(String stringNumber)
{
if(stringNumber.isEmpty())
{
return false;
}
stringNumber = stringNumber.replaceAll(" ", "");
char [] charNumber = stringNumber.toCharArray();
for(int i =0 ; i<charNumber.length ;i++)
{
if(!Character.isDigit(charNumber[i]))
{
return false;
}
}
return true;
}
Oto inna metoda na wypadek, gdybyś chciał zezwolić na liczbę zmiennoprzecinkową. Ta metoda rzekomo pozwala na przekazanie liczb w formularzu 1,123,123,123,123,123.123 właśnie ją stworzyłem i myślę, że wymaga dalszych testów, aby upewnić się, że działa.
private boolean isValidStringTrueNumber(String stringNumber)
{
if(stringNumber.isEmpty())
{
return false;
}
stringNumber = stringNumber.replaceAll(" ", "");
int countOfDecimalPoint = 0;
boolean decimalPointPassed = false;
boolean commaFound = false;
int countOfDigitsBeforeDecimalPoint = 0;
int countOfDigitsAfterDecimalPoint =0 ;
int commaCounter=0;
int countOfDigitsBeforeFirstComma = 0;
char [] charNumber = stringNumber.toCharArray();
for(int i =0 ; i<charNumber.length ;i++)
{
if((commaCounter>3)||(commaCounter<0))
{
return false;
}
if(!Character.isDigit(charNumber[i]))//Char is not a digit.
{
if(charNumber[i]==',')
{
if(decimalPointPassed)
{
return false;
}
commaFound = true;
//check that next three chars are only digits.
commaCounter +=3;
}
else if(charNumber[i]=='.')
{
decimalPointPassed = true;
countOfDecimalPoint++;
}
else
{
return false;
}
}
else //Char is a digit.
{
if ((commaCounter>=0)&&(commaFound))
{
if(!decimalPointPassed)
{
commaCounter--;
}
}
if(!commaFound)
{
countOfDigitsBeforeFirstComma++;
}
if(!decimalPointPassed)
{
countOfDigitsBeforeDecimalPoint++;
}
else
{
countOfDigitsAfterDecimalPoint++;
}
}
}
if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
{
return false;
}
if(countOfDecimalPoint>1)
{
return false;
}
if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
{
return false;
}
return true;
}