Java-Zeichenfolge - Überprüfen Sie, ob eine Zeichenfolge nur Zahlen und keine Buchstaben enthält

195

Ich habe eine Zeichenfolge, die ich in meiner gesamten Anwendung lade und die sich von Zahlen zu Buchstaben und dergleichen ändert. Ich habe eine einfache ifAussage, um zu sehen, ob sie Buchstaben oder Zahlen enthält, aber etwas funktioniert nicht ganz richtig. Hier ist ein Ausschnitt.

String text = "abc"; 
String number; 

if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
    number = text; 
}

Obwohl die textVariable Buchstaben enthält, gibt die Bedingung as zurück true. Das und &&sollte als beide Bedingungen ausgewertet werden, trueum das zu verarbeitennumber = text;

==============================

Lösung:

Ich konnte dies mithilfe des folgenden Codes lösen, der durch einen Kommentar zu dieser Frage bereitgestellt wurde. Alle anderen Beiträge sind ebenfalls gültig!

Was ich verwendet habe, das funktioniert hat, kam aus dem ersten Kommentar. Obwohl alle angegebenen Beispielcodes ebenfalls gültig zu sein scheinen!

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}
RedHatcc
quelle
5
enthält nimmt keinen regulären Ausdruck als Eingabe. Verwenden Sie entweder matches("\\d{2,}")oder versuchen Sie es mit einem PatternundMatcher
Guillaume Polet
Kann die Zeichenfolge einen Dezimalwert oder nur ganzzahlige Werte haben?
Pseudoramble
3
Warum überprüfen Sie text.length ()> 2? Was ist der Grund?
Code Enthusiastic
1
@ RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsekann vereinfacht werden!Pattern.matches("[a-zA-Z]+", text)
SARose
2
Verwenden der Java-Streaming-API- boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));Formular Max MalyshPost.
Yash

Antworten:

354

Wenn Sie die Nummer als Text verarbeiten, ändern Sie:

if (text.contains("[a-zA-Z]+") == false && text.length() > 2){

zu:

if (text.matches("[0-9]+") && text.length() > 2) {

Anstatt zu überprüfen, ob die Zeichenfolge keine alphabetischen Zeichen enthält, stellen Sie sicher, dass sie nur numerische Zeichen enthält .

Wenn Sie den numerischen Wert tatsächlich verwenden möchten, verwenden Sie Integer.parseInt()oder Double.parseDouble()wie andere unten erläutert haben.


Als Randnotiz wird es allgemein als schlechte Praxis angesehen, boolesche Werte mit trueoder zu vergleichen false. Verwenden Sie einfach if (condition)oder if (!condition).

Adam Liss
quelle
25
Sie möchten wahrscheinlich Anker hinzufügen (z. B. ^[0-9]+$), andernfalls abc123defwird dies als Zahl betrachtet.
ICR
10
Ich denke nicht, dass das erforderlich ist. matches()Gibt nur dann true zurück, wenn es sich um eine vollständige Übereinstimmung von Anfang bis Ende handelt.
Chthonic Project
4
"^ -? \ d + \.? \ d * $" vergleicht die gesamte Zeichenfolge und stimmt nur überein, wenn es sich um eine gültige Zahl handelt (Negative und Dezimalstellen enthalten). Zum Beispiel wird es mit 1, 10, 1.0, -1, -1.0 usw. übereinstimmen. Es wird auch mit "1" übereinstimmen. aber das kann sowieso oft analysiert werden.
16
Es besteht keine Notwendigkeit anzurufen && (text.length() > 2). Alles kann im Regex-Muster überprüft werden:if (text.matches("[0-9]{3,}")
Ctomek
Was ist mit Kommas oder Punkten für Zahlen, die keine ganzen Zahlen sind?
Nibbana
20

Sie können auch NumberUtil.isCreatable (String str) von Apache Commons verwenden

Dhrumil Shah
quelle
4
Ich denke nicht, dass NumberUtil.isCreatable(String str)es richtig ist, das zu verwenden, was die ursprüngliche Frage verlangt. ZB gibt NumberUtil.isCreatable( "09" )zurück false, obwohl es "09" nur Zahlen enthält .
Abdull
14

So würde ich es machen:

if(text.matches("^[0-9]*$") && text.length() > 2){
    //...
}

Dadurch $wird eine teilweise Übereinstimmung vermieden, z. 1B.

tokhi
quelle
1
Ich brauche nicht den text.length() > 2Teil, so dass ich nur ersetzt ^[0-9]*$durch ^[0-9]+$sicher sein , ich habe mindestens eine Zahl.
YB Ursache
8

In parseIntBezug auf die Leistung und dergleichen sind sie viel schlechter als andere Lösungen, da zumindest eine Ausnahmebehandlung erforderlich ist.

Ich habe jmh-Tests ausgeführt und festgestellt, dass das Überlaufen von String using charAt und das Vergleichen von Zeichen mit Grenzzeichen der schnellste Weg ist, um zu testen, ob der String nur Ziffern enthält.

JMH-Tests

Tests vergleichen die Leistung von Character.isDigitvs Pattern.matcher().matchesvs.Long.parseLong vs überprüfen Zeichenwerte.

Diese Methoden können zu unterschiedlichen Ergebnissen für Nicht-ASCII-Zeichenfolgen und Zeichenfolgen mit +/- Zeichen führen.

Tests werden im Durchsatzmodus ausgeführt ( größer ist besser ) mit 5 Aufwärmiterationen und 5 Testiterationen ausgeführt.

Ergebnisse

Beachten Sie, dass dies parseLongfast 100-mal langsamer ist als isDigitbei der ersten Testlast.

## Test load with 25% valid strings (75% strings contain non-digit symbols)

Benchmark       Mode  Cnt  Score   Error  Units
testIsDigit    thrpt    5  9.275 ± 2.348  ops/s
testPattern    thrpt    5  2.135 ± 0.697  ops/s
testParseLong  thrpt    5  0.166 ± 0.021  ops/s

## Test load with 50% valid strings (50% strings contain non-digit symbols)

Benchmark              Mode  Cnt  Score   Error  Units
testCharBetween       thrpt    5  16.773 ± 0.401  ops/s
testCharAtIsDigit     thrpt    5  8.917 ± 0.767  ops/s
testCharArrayIsDigit  thrpt    5  6.553 ± 0.425  ops/s
testPattern           thrpt    5  1.287 ± 0.057  ops/s
testIntStreamCodes    thrpt    5  0.966 ± 0.051  ops/s
testParseLong         thrpt    5  0.174 ± 0.013  ops/s
testParseInt          thrpt    5  0.078 ± 0.001  ops/s

Testsuite

@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
    private static final long CYCLES = 1_000_000L;
    private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Benchmark
    public void testPattern() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = PATTERN.matcher(s).matches();
            }
        }
    }

    @Benchmark
    public void testParseLong() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                try {
                    Long.parseLong(s);
                    b = true;
                } catch (NumberFormatException e) {
                    // no-op
                }
            }
        }
    }

    @Benchmark
    public void testCharArrayIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (char c : s.toCharArray()) {
                    b = Character.isDigit(c);
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testCharAtIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    b = Character.isDigit(s.charAt(j));
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testIntStreamCodes() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = s.chars().allMatch(c -> c > 47 && c < 58);
            }
        }
    }

    @Benchmark
    public void testCharBetween() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    char charr = s.charAt(j);
                    b = '0' <= charr && charr <= '9';
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }
}

Aktualisiert am 23. Februar 2018

  • Fügen Sie zwei weitere Fälle hinzu - einen mithilfe charAteines zusätzlichen Arrays und einen mithilfe IntStreamvon Zeichencodes
  • Fügen Sie eine sofortige Unterbrechung hinzu, wenn für Testfälle mit Schleifen keine Ziffer gefunden wurde
  • Geben Sie false für eine leere Zeichenfolge für Testfälle mit Schleifen zurück

Aktualisiert am 23. Februar 2018

  • Fügen Sie einen weiteren Testfall hinzu (den schnellsten!), Der den Zeichenwert ohne Verwendung von Stream vergleicht
Anton R.
quelle
1
Wenn Sie sich den Code von toCharArray ansehen, wird ein Zeichenarray zugewiesen und die Zeichen kopiert (ich denke, das könnte teuer sein). Was wäre, wenn Sie die Zeichenfolge nur mit einem Index und charAt iterieren würden, wäre es schneller? Wäre auch interessant, wenn Sie die Lösung von Andy zu Ihren Tests hinzufügen könnten: boolean isNum = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa
8

Verwenden Sie den folgenden Code, um einfach zu überprüfen, ob die Zeichenfolge nur ALPHABETS enthält:

if (text.matches("[a-zA-Z]+"){
   // your operations
}

Verwenden Sie den folgenden Code, um einfach zu überprüfen, ob die Zeichenfolge nur NUMBER enthält:

if (text.matches("[0-9]+"){
   // your operations
}

Hoffe das wird jemandem helfen!

Aman Kumar Gupta
quelle
3

boolean isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)

Andy
quelle
1
Um magische Zahlen zu reduzieren, können Sie wie folgt vergleichen:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix
2

Sie können Regex.Match verwenden

if(text.matches("\\d*")&& text.length() > 2){
    System.out.println("number");
}

Oder Sie könnten Onversionen wie Integer.parseInt(String)oder besser Long.parseLong(String)für größere Zahlen verwenden, wie zum Beispiel:

private boolean onlyContainsNumbers(String text) {
    try {
        Long.parseLong(text);
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }
} 

Und dann testen mit:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}
Yannjoel
quelle
.matches ("^ \\ d + $")
CrandellWS
2

Die folgenden regulären Ausdrücke können verwendet werden, um zu überprüfen, ob eine Zeichenfolge nur eine Nummer hat oder nicht:

if (str.matches(".*[^0-9].*")) or if (str.matches(".*\\D.*"))

Beide oben genannten Bedingungen werden zurückgegeben, truewenn String Nicht-Zahlen enthält. Ein false, Zeichenfolge hat nur Zahlen.

Nitesh Shrivastava
quelle
2

Apache Commons Lang stellt org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs)als Argument a zur Verfügung Stringund prüft, ob es aus rein numerischen Zeichen besteht (einschließlich Zahlen aus nicht-lateinischen Skripten). Diese Methode gibt zurückfalse wenn Zeichen wie Leerzeichen, Minuszeichen, Pluszeichen und Dezimaltrennzeichen wie Komma und Punkt vorhanden sind.

Andere Methoden dieser Klasse ermöglichen weitere numerische Überprüfungen.

Abdull
quelle
1
Dies sollte viel schneller sein als ein regulärer Ausdruck. Hier ist die Implementierung: public static boolean isNumeric(String str) { if (str == null) { return false; } else { int sz = str.length(); for(int i = 0; i < sz; ++i) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } }
Leo
1

Es gibt viele Möglichkeiten, Zahlen von Strings in Java zu erhalten (und umgekehrt). Möglicherweise möchten Sie den Regex-Teil überspringen, um sich die Komplikation zu ersparen.

Sie könnten beispielsweise versuchen, herauszufinden, was Double.parseDouble(String s)für Sie zurückkehrt. Es sollte a auslösen, NumberFormatExceptionwenn es keinen geeigneten Wert in der Zeichenfolge findet. Ich würde diese Technik vorschlagen, da Sie den durch das dargestellten Wert tatsächlich Stringals numerischen Typ verwenden könnten .

Pseudoramble
quelle
5
Die Verwendung einer Ausnahme als Grund für das Testen Ihrer Eingabe ist möglicherweise eine schlechte Idee. Ausnahmen verursachen einen hohen Overhead.
Ofir Luzon
1
@OfirLuzon Ich stimme zu, dass Ausnahmen keine gute Möglichkeit sind, erwartete Fälle zu behandeln, die auftreten werden. Ich denke jedoch, es ist schwer zu sagen, ob es einen Performance-Hit ohne mehr Kontext geben würde.
Pseudoramble
1

Hier ist mein Code, hoffe das wird dir helfen!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

    if (text.matches("[0-9]+") && text.length() > 2) {
        isDigit = true;
    }else {
        isDigit = false;
    }

    return isDigit;
}
Saurabh Gaddelpalliwar
quelle
0

Dieser Code ist bereits geschrieben. Wenn Ihnen der (extrem) geringfügige Leistungseinbruch nichts ausmacht - der wahrscheinlich nicht schlechter ist als ein Regex-Match -, verwenden Sie Integer.parseInt () oder Double.parseDouble () . Das wird Ihnen sofort sagen, ob ein String nur aus Zahlen besteht (oder gegebenenfalls aus einer Zahl). Wenn Sie längere Zahlenfolgen verarbeiten müssen, verwenden sowohl BigInteger- als auch BigDecimal - Sportkonstruktoren Zeichenfolgen. Jedes dieser Elemente löst eine NumberFormatException wenn Sie versuchen, eine Nicht-Zahl zu übergeben (ganzzahlig oder dezimal, natürlich basierend auf der von Ihnen ausgewählten). Alternativ können Sie je nach Ihren Anforderungen einfach die Zeichen in der Zeichenfolge iterieren und Character.isDigit () überprüfen.und / oder Character.isLetter () .

Ryan Stewart
quelle
0
import java.util.*;

class Class1 {
    public static void main(String[] argh) {
        boolean ans = CheckNumbers("123");
        if (ans == true) {
            System.out.println("String contains numbers only");
        } else {
            System.out.println("String contains other values as well");

        }
    }


    public static boolean CheckNumbers(String input) {
        for (int ctr = 0; ctr < input.length(); ctr++) {
            if ("1234567890".contains(Character.valueOf(input.charAt(ctr)).toString())) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }
}
Usman Javaid
quelle
0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }
JamisonMan111
quelle
0

Beispiel für einen Arbeitstest

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

        if (!StringUtils.isBlank(text)) {
            if (stringContainsNumber(text)) {
                int no=Integer.parseInt(text.trim());
                System.out.println("inside"+no);

            } else {
                System.out.println("Outside");
            }
        }
        System.out.println("Done");
    }

    public static boolean stringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
}

Trotzdem kann Ihr Code durch "1a" usw. unterbrochen werden, sodass Sie die Ausnahme überprüfen müssen

if (!StringUtils.isBlank(studentNbr)) {
                try{
                    if (isStringContainsNumber(studentNbr)){
                    _account.setStudentNbr(Integer.parseInt(studentNbr.trim()));
                }
                }catch(Exception e){
                    e.printStackTrace();
                    logger.info("Exception during parse studentNbr"+e.getMessage());
                }
            }

Die Methode zum Überprüfen von no ist string oder nicht

private boolean isStringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
Vaquar Khan
quelle
0

Es ist eine schlechte Praxis, Ausnahmen in ein solches typisches Szenario zu werfen.

Daher ist ein parseInt () nicht schön, aber ein
regulärer
Ausdruck ist eine elegante Lösung dafür. Achten Sie jedoch auf Folgendes: - Brüche - negative Zahlen
- Dezimaltrennzeichen können sich manchmal in Kontra (z. B. ',' oder '.')
Unterscheiden Es darf ein sogenanntes Tausendertrennzeichen wie ein Leerzeichen oder ein Komma haben, z. B. 12.324.1000.355

Um alle erforderlichen Fälle in Ihrer Anwendung zu behandeln, müssen Sie vorsichtig sein. Dieser reguläre Ausdruck deckt jedoch die typischen Szenarien ab (positiv / negativ und gebrochen, durch einen Punkt getrennt): ^ [- +]? \ D *.? \ D + $
For Testen empfehle ich regexr.com .

Adam Bodrogi
quelle
0

Leicht modifizierte Version von Adam Bodrogi:

public class NumericStr {


public static void main(String[] args) {
    System.out.println("Matches: "+NumericStr.isNumeric("20"));         // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("20,00"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30,000.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("-2980"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("$20"));            // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("jdl"));            // Should be false
    System.out.println("Matches: "+NumericStr.isNumeric("2lk0"));           // Should be false
}

public static boolean isNumeric(String stringVal) {
    if (stringVal.matches("^[\\$]?[-+]?[\\d\\.,]*[\\.,]?\\d+$")) {
        return true;
    }

    return false;
}
}

Musste dies heute verwenden, also habe ich gerade meine Änderungen gepostet. Beinhaltet Währung, Tausend Komma oder Punktnotation und einige Validierungen. Enthält keine anderen Währungsnotationen (Euro, Cent), Bestätigungskommas sind jede dritte Ziffer.

user176692
quelle