Wie extrahiere ich Zahlen aus einer Zeichenfolge und erhalte ein Array von Ints?

109

Ich habe eine String-Variable (im Grunde ein englischer Satz mit einer nicht angegebenen Anzahl von Zahlen) und möchte alle Zahlen in ein Array von Ganzzahlen extrahieren. Ich habe mich gefragt, ob es eine schnelle Lösung mit regulären Ausdrücken gibt.


Ich habe Seans Lösung verwendet und sie leicht geändert:

LinkedList<String> numbers = new LinkedList<String>();

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}
John Manak
quelle
1
Sind Zahlen von Leerzeichen oder anderen Zeichen umgeben? Wie werden Zahlen formatiert, sind sie hexadezimal, oktal, binär, dezimal?
Buhake Sindi
Ich dachte, es wäre klar aus der Frage: Es ist ein englischer Satz mit Zahlen. Außerdem habe ich über ein Integer-Array gesprochen, also habe ich nach Integer gesucht.
John Manak

Antworten:

175
Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There are more than -2 and less than 12 numbers here");
while (m.find()) {
  System.out.println(m.group());
}

... druckt -2und 12.


-? entspricht einem führenden negativen Vorzeichen - optional. \ d stimmt mit einer Ziffer überein, und wir müssen jedoch \wie \\in einem Java-String schreiben . \ D + entspricht also einer oder mehreren Ziffern.

Sean Owen
quelle
4
Könnten Sie Ihre Antwort bitte durch eine Erklärung Ihres regulären Ausdrucks ergänzen?
OscarRyz
3
-? entspricht einem führenden negativen Vorzeichen - optional. \ d stimmt mit einer Ziffer überein, und wir müssen jedoch \ as \\ in einen Java-String schreiben. Also, \\ d + entspricht 1 weiteren Ziffern
Sean Owen
7
Ich habe meinen Ausdruck in Pattern.compile ("-? [\\ d \\.] +") Geändert, um Floats zu unterstützen. Du führst mich definitiv auf den Weg, Thx!
Jlengrand
Diese Methode erkennt Ziffern, erkennt jedoch keine formulierten Zahlen, z 2,000. Für eine solche Verwendung-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba
Das unterstützt nur ein einziges Komma, würde also "2.000.000" verpassen. Es werden auch Zeichenfolgen wie "2,00" akzeptiert. Wenn Komma-Trennzeichen unterstützt werden müssen, -?\\d+(,\\d{3})*sollte : funktionieren.
Sean Owen
52

Was ist mit der replaceAllMethode java.lang.String ?

    String str = "qwerty-1qwerty-2 455 f0gfg 4";      
    str = str.replaceAll("[^-?0-9]+", " "); 
    System.out.println(Arrays.asList(str.trim().split(" ")));

Ausgabe:

[-1, -2, 455, 0, 4]

Beschreibung

[^-?0-9]+
  • [und ]begrenzt eine Reihe von Zeichen, die einzeln abgeglichen werden sollen, dh nur einmal in beliebiger Reihenfolge
  • ^Spezielle Kennung, die am Anfang des Satzes verwendet wird und angibt, dass alle Zeichen, die nicht im begrenzten Satz vorhanden sind, anstelle aller im Satz vorhandenen Zeichen übereinstimmen .
  • + Zwischen einer und einer unbegrenzten Zeit, so oft wie möglich, und nach Bedarf etwas zurückgeben
  • -? Eine der Figuren "-" und "?"
  • 0-9 Ein Zeichen im Bereich zwischen "0" und "9"
Maxim Shoustin
quelle
4
Warum sollten Sie Fragezeichen behalten wollen? Auch diese Leckereien für -sich als eine Zahl, zusammen mit Dingen wie 9-, ---6, und 1-2-3.
Alan Moore
1
Eine sehr schöne Alternative ohne Import von Bibliotheken;)
Jcc.Sanabria
18
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(myString);
while (m.find()) {
    int n = Integer.parseInt(m.group());
    // append n to list
}
// convert list to array, etc

Sie können [0-9] tatsächlich durch \ d ersetzen, dies beinhaltet jedoch das Entkommen eines doppelten Backslashs, was das Lesen erschwert.

siderisch
quelle
Hoppla. Sean's behandelt negative Zahlen, das ist also eine Verbesserung.
siderisch
2
Ihre werden auch negative Zahlen behandeln, wenn Sie "-? [0-9] +"
cegprakash
9
  StringBuffer sBuffer = new StringBuffer();
  Pattern p = Pattern.compile("[0-9]+.[0-9]*|[0-9]*.[0-9]+|[0-9]+");
  Matcher m = p.matcher(str);
  while (m.find()) {
    sBuffer.append(m.group());
  }
  return sBuffer.toString();

Dies dient zum Extrahieren von Zahlen, bei denen die Dezimalstelle beibehalten wird

Kannan
quelle
Behandelt
5

Die akzeptierte Antwort erkennt Ziffern, aber keine formulierten Zahlen, z. B. 2.000, noch Dezimalstellen, z. B. 4.8. Für eine solche Verwendung -?\\d+(,\\d+)*?\\.?\\d+?:

        Pattern p = Pattern.compile("-?\\d+(,\\d+)*?\\.?\\d+?");
        List<String> numbers = new ArrayList<String>();
        Matcher m = p.matcher("Government has distributed 4.8 million textbooks to 2,000 schools");
        while (m.find()) {  
            numbers.add(m.group());
        }   
        System.out.println(numbers);

Ausgabe: [4.8, 2,000]

Mugoma J. Okomba
quelle
1
@ JulienS.: Ich bin anderer Meinung. Diese Regex macht viel mehr als das OP verlangt, und es macht falsch. (Zumindest sollte der Dezimalteil in einer optionalen Gruppe sein, mit allem, was darin erforderlich und gierig ist : (?:\.\d+)?.)
Alan Moore
Sie haben dort sicherlich einen Punkt für den Dezimalteil. Es ist jedoch sehr häufig, dass formatierte Zahlen auftreten.
Julien
@AlanMoore viele Besucher von SO suchen nach verschiedenen Möglichkeiten, um Probleme mit unterschiedlicher Ähnlichkeit / Unterschiedlichkeit zu lösen, und es ist hilfreich, Vorschläge zu machen. Sogar das OP könnte sich zu stark vereinfacht haben.
Mugoma J. Okomba
4

für rationale Zahlen verwenden Sie diese: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))

Andrey
quelle
1
Das OP sagte ganze Zahlen, keine reellen Zahlen. Außerdem haben Sie vergessen, den Punkten zu entkommen, und keine dieser Klammern ist erforderlich.
Alan Moore
3

Mit Java 8 können Sie Folgendes tun:

String str = "There 0 are 1 some -2-34 -numbers 567 here 890 .";
int[] ints = Arrays.stream(str.replaceAll("-", " -").split("[^-\\d]+"))
                 .filter(s -> !s.matches("-?"))
                 .mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

Wenn Sie keine negativen Zahlen haben, können Sie die replaceAll(und !s.isEmpty()in filter) verwenden, da dies nur dazu dient, etwas wie richtig aufzuteilen 2-34(dies kann auch nur mit Regex in behandelt werden split, ist aber ziemlich kompliziert).

Arrays.streamverwandelt unsere String[]in eine Stream<String>.

filterentfernt die führenden und nachfolgenden leeren Zeichenfolgen sowie alle Zeichenfolgen -, die nicht Teil einer Zahl sind.

mapToInt(Integer::parseInt).toArray()fordert parseIntjeden Stringauf, uns eine zu geben int[].


Alternativ verfügt Java 9 über eine Matcher.results- Methode, die Folgendes ermöglichen sollte:

Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There 0 are 1 some -2-34 -numbers 567 here 890 .");
int[] ints = m.results().map(MatchResults::group).mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

So wie es aussieht, ist keines von beiden eine große Verbesserung gegenüber dem einfachen Durchlaufen der Ergebnisse mit Pattern/, Matcherwie in den anderen Antworten gezeigt, aber es sollte einfacher sein, wenn Sie dies mit komplexeren Operationen verfolgen möchten, die durch die Verwendung von erheblich vereinfacht werden Streams.

Bernhard Barker
quelle
1

Extrahieren Sie damit alle reellen Zahlen.

public static ArrayList<Double> extractNumbersInOrder(String str){

    str+='a';
    double[] returnArray = new double[]{};

    ArrayList<Double> list = new ArrayList<Double>();
    String singleNum="";
    Boolean numStarted;
    for(char c:str.toCharArray()){

        if(isNumber(c)){
            singleNum+=c;

        } else {
            if(!singleNum.equals("")){  //number ended
                list.add(Double.valueOf(singleNum));
                System.out.println(singleNum);
                singleNum="";
            }
        }
    }

    return list;
}


public static boolean isNumber(char c){
    if(Character.isDigit(c)||c=='-'||c=='+'||c=='.'){
        return true;
    } else {
        return false;
    }
}
Prahlerei 68
quelle
1

Bruch- und Gruppierungszeichen zur Darstellung reeller Zahlen können zwischen den Sprachen unterschiedlich sein. Die gleiche reelle Zahl kann je nach Sprache sehr unterschiedlich geschrieben werden.

Die Nummer zwei Millionen auf Deutsch

2.000.000,00

und auf Englisch

2.000.000,00

Eine Methode zum vollständigen Extrahieren von reellen Zahlen aus einer bestimmten Zeichenfolge auf sprachunabhängige Weise:

public List<BigDecimal> extractDecimals(final String s, final char fraction, final char grouping) {
    List<BigDecimal> decimals = new ArrayList<BigDecimal>();
    //Remove grouping character for easier regexp extraction
    StringBuilder noGrouping = new StringBuilder();
    int i = 0;
    while(i >= 0 && i < s.length()) {
        char c = s.charAt(i);
        if(c == grouping) {
            int prev = i-1, next = i+1;
            boolean isValidGroupingChar =
                    prev >= 0 && Character.isDigit(s.charAt(prev)) &&
                    next < s.length() && Character.isDigit(s.charAt(next));                 
            if(!isValidGroupingChar)
                noGrouping.append(c);
            i++;
        } else {
            noGrouping.append(c);
            i++;
        }
    }
    //the '.' character has to be escaped in regular expressions
    String fractionRegex = fraction == POINT ? "\\." : String.valueOf(fraction);
    Pattern p = Pattern.compile("-?(\\d+" + fractionRegex + "\\d+|\\d+)");
    Matcher m = p.matcher(noGrouping);
    while (m.find()) {
        String match = m.group().replace(COMMA, POINT);
        decimals.add(new BigDecimal(match));
    }
    return decimals;
}
Und wir
quelle
1

Wenn Sie Zahlen ausschließen möchten, die in Wörtern enthalten sind, z. B. bar1 oder aa1bb, fügen Sie einer der auf Regex basierenden Antworten Wortgrenzen \ b hinzu. Beispielsweise:

Pattern p = Pattern.compile("\\b-?\\d+\\b");
Matcher m = p.matcher("9There 9are more9 th9an -2 and less than 12 numbers here9");
while (m.find()) {
  System.out.println(m.group());
}

zeigt an:

2
12
dxl
quelle
1

Ich würde vorschlagen, die ASCII-Werte zu überprüfen, um Zahlen aus einer Zeichenfolge zu extrahieren. Angenommen, Sie haben eine Eingabezeichenfolge als myname12345. Wenn Sie nur die Zahlen 12345 extrahieren möchten, können Sie dies tun, indem Sie zuerst die Zeichenfolge in ein Zeichenarray konvertieren und dann den folgenden Pseudocode verwenden

    for(int i=0; i < CharacterArray.length; i++)
    {
        if( a[i] >=48 && a[i] <= 58)
            System.out.print(a[i]);
    }

Sobald die Zahlen extrahiert sind, hängen Sie sie an ein Array an

Hoffe das hilft

The_Fresher
quelle
Eine Java-Zeichenfolge wird als Folge von Unicode / UTF-16-Codeeinheiten gezählt. Durch das Design von UTF-16 haben die ersten 128 Zeichen den gleichen Wert (nicht die gleiche Größe) wie ihre ASCII-Codierung. Darüber hinaus führt der Gedanke, dass Sie mit ASCII zu tun haben, zu Fehlern.
Tom Blodget
0

Ich fand diesen Ausdruck am einfachsten

String[] extractednums = msg.split("\\\\D++");
user2902302
quelle
-1
public static String extractNumberFromString(String number) {
    String num = number.replaceAll("[^0-9]+", " ");
    return num.replaceAll(" ", "");
}

extrahiert nur Zahlen aus der Zeichenfolge

user3509903
quelle