Come estrarre i numeri da una stringa e ottenere un array di int?


109

Ho una variabile String (fondamentalmente una frase inglese con un numero di numeri non specificato) e vorrei estrarre tutti i numeri in un array di numeri interi. Mi chiedevo se ci fosse una soluzione rapida con le espressioni regolari?


Ho usato la soluzione di Sean e l'ho leggermente modificata:

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

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}

1
I numeri sono circondati da spazi o altri caratteri? Come vengono formattati i numeri, sono esadecimali, ottali, binari, decimali?
Buhake Sindi

Ho pensato che fosse chiaro dalla domanda: è una frase inglese con numeri. Inoltre stavo parlando di un array di numeri interi, quindi quello che stavo cercando erano numeri interi.
John Manak

Risposte:


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

... stampe -2e 12.


-? corrisponde a un segno negativo iniziale - facoltativamente. \ d corrisponde a una cifra, e tuttavia dobbiamo scrivere \come \\in una stringa Java. Quindi, \ d + corrisponde a 1 o più cifre.


4
Potresti completare la tua risposta spiegando la tua espressione regolare per favore?
OscarRyz

3
-? corrisponde a un segno negativo iniziale - facoltativamente. \ d corrisponde a una cifra e dobbiamo scrivere \ come \\ in una stringa Java. Quindi, \\ d + corrisponde a 1 altra cifra in più
Sean Owen

7
Ho cambiato la mia espressione in Pattern.compile ("-? [\\ d \\.] +") Per supportare i float. Mi hai decisamente guidato sulla strada, Thx!
jlengrand

Questo metodo rileva le cifre ma non rileva i numeri formattati, ad es 2,000. Per tale uso-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba

Questo supporta solo una singola virgola, quindi mancherebbe "2.000.000". Accetta anche stringhe come "2,00". Se i separatori virgola devono essere supportati, allora: -?\\d+(,\\d{3})*dovrebbe funzionare.
Sean Owen

52

Che ne dici di usare il replaceAllmetodo java.lang.String:

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

Produzione:

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

Descrizione

[^-?0-9]+
  • [e ]delimita un insieme di caratteri a cui corrispondere una sola volta, cioè solo una volta in qualsiasi ordine
  • ^Identificatore speciale utilizzato all'inizio del set, utilizzato per indicare di abbinare tutti i caratteri non presenti nel set delimitato, invece di tutti i caratteri presenti nel set.
  • + Da una a illimitate, quante più volte possibile, restituendo se necessario
  • -? Uno dei caratteri "-" e "?"
  • 0-9 Un carattere nell'intervallo tra "0" e "9"

4
Perché vuoi mantenere i punti interrogativi? Inoltre, questo tratta -di per sé come un numero, insieme con le cose come 9-, ---6e 1-2-3.
Alan Moore

1
Un'alternativa molto carina senza usare le librerie di importazione;)
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

Puoi effettivamente sostituire [0-9] con \ d, ma ciò implica l'escape di una doppia barra rovesciata, il che rende più difficile la lettura.


Ops. Sean's gestisce i numeri negativi, quindi è un miglioramento.
siderale

2
il tuo gestirà anche i numeri negativi se usi "-? [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();

Serve per estrarre i numeri mantenendo il decimale


Non gestisce gli
aspetti

5

La risposta accettata rileva le cifre ma non i numeri formattati, ad esempio 2.000, né i decimali, ad esempio 4.8. Per tale uso -?\\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);

Produzione: [4.8, 2,000]


1
@ JulienS .: Non sono d'accordo. Questa regex fa molto di più di quanto richiesto dall'OP e lo fa in modo errato. (Almeno, la parte decimale dovrebbe essere in un gruppo opzionale, con tutto ciò che è richiesto e avido:. (?:\.\d+)?)
Alan Moore

Hai sicuramente un punto per la parte decimale. Tuttavia è molto comune incontrare numeri formattati.
Julien

@AlanMoore molti visitatori di SO stanno cercando modi diversi per risolvere problemi con somiglianze / differenze variabili, ed è utile che vengano presentati suggerimenti. Anche l'OP potrebbe essere semplificato eccessivamente.
Mugoma J. Okomba

4

per i numeri razionali usa questo: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))


1
L'OP ha detto numeri interi, non numeri reali. Inoltre, hai dimenticato di sfuggire ai punti e nessuna di queste parentesi è necessaria.
Alan Moore

3

Utilizzando Java 8, puoi fare:

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]

Se non hai numeri negativi, puoi sbarazzarti di replaceAll(e usare !s.isEmpty()in filter), poiché è solo per dividere correttamente qualcosa di simile 2-34(questo può anche essere gestito esclusivamente con regex in split, ma è abbastanza complicato).

Arrays.streamtrasforma il nostro String[]in un file Stream<String>.

filterelimina le stringhe vuote iniziali e finali e quelle -che non fanno parte di un numero.

mapToInt(Integer::parseInt).toArray()chiede parseInta ciascuno Stringdi darci un int[].


In alternativa, Java 9 ha un metodo Matcher.results , che dovrebbe consentire qualcosa come:

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]

Allo stato attuale, nessuno di questi è un grande miglioramento rispetto al semplice ciclo dei risultati con Pattern/ Matchercome mostrato nelle altre risposte, ma dovrebbe essere più semplice se vuoi seguirlo con operazioni più complesse che sono notevolmente semplificate con l'uso di flussi.


1

Estrai tutti i numeri reali usando questo.

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

1

I caratteri frazionari e di raggruppamento per rappresentare i numeri reali possono differire tra le lingue. Lo stesso numero reale potrebbe essere scritto in modi molto diversi a seconda della lingua.

Il numero due milioni in tedesco

2.000.000,00

e in inglese

2.000.000,00

Un metodo per estrarre completamente i numeri reali da una data stringa in modo indipendente dalla lingua:

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

1

Se desideri escludere i numeri contenuti all'interno di parole, come bar1 o aa1bb, aggiungi i confini delle parole \ b a qualsiasi risposta basata su espressioni regolari. Per esempio:

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

display:

2
12

1

Suggerirei di controllare i valori ASCII per estrarre i numeri da una stringa Supponiamo di avere una stringa di input come myname12345 e se desideri estrarre solo i numeri 12345 puoi farlo convertendo prima la stringa in Character Array, quindi utilizzare il seguente pseudocodice

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

una volta estratti i numeri, aggiungili a un array

Spero che questo ti aiuti


Una stringa Java è una sequenza conteggiata di unità di codice Unicode / UTF-16. In base alla progettazione di UTF-16, i primi 128 caratteri hanno lo stesso valore (ma non la stessa dimensione) della loro codifica ASCII; Oltre a ciò, pensare di avere a che fare con ASCII porterà a errori.
Tom Blodget

0

Ho trovato questa espressione più semplice

String[] extractednums = msg.split("\\\\D++");

-1
public static String extractNumberFromString(String number) {
    String num = number.replaceAll("[^0-9]+", " ");
    return num.replaceAll(" ", "");
}

estrae solo numeri dalla stringa

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.