Utilizzo delle espressioni regolari per estrarre un valore in Java


169

Ho diverse stringhe in forma approssimativa:

[some text] [some number] [some more text]

Voglio estrarre il testo in [alcuni numeri] usando le classi Java Regex.

So più o meno quale espressione regolare voglio usare (anche se tutti i suggerimenti sono ben accetti). Quello che mi interessa veramente sono le chiamate Java per prendere la stringa regex e usarla sui dati di origine per produrre il valore di [un certo numero].

EDIT: dovrei aggiungere che mi interessa solo un singolo [un certo numero] (in sostanza, la prima istanza). Le stringhe di origine sono brevi e non cercherò più occorrenze di [un certo numero].


11
... e ora vado alla ricerca. Vediamo se SO può ottenere una risposta per me prima di capirlo da solo. :-P
— Craig Walker,

questo è stato un colloquio con una società bancaria / di investimento / commerciale per l'ingegneria del software, no? : P
— ennth

@enn No. No, nemmeno vicino! Era per il codice di produzione su un sito Web di piccole dimensioni ... molte lune fa.
— Craig Walker

1
dannatamente bene mi è stata posta la stessa identica domanda su un esame di codifica JP Morgan Chase Software Engineering pochi giorni fa: P
— ennth

Risposte:


316

Esempio completo:

private static final Pattern p = Pattern.compile("^([a-zA-Z]+)([0-9]+)(.*)");
public static void main(String[] args) {
    // create matcher for pattern p and given string
    Matcher m = p.matcher("Testing123Testing");

    // if an occurrence if a pattern was found in a given string...
    if (m.find()) {
        // ...then you can use group() methods.
        System.out.println(m.group(0)); // whole matched expression
        System.out.println(m.group(1)); // first expression from round brackets (Testing)
        System.out.println(m.group(2)); // second one (123)
        System.out.println(m.group(3)); // third one (Testing)
    }
}

Poiché stai cercando il primo numero, puoi utilizzare tale regexp:

^\D+(\d+).*

e m.group(1)ti restituirà il primo numero. Si noti che i numeri con segno possono contenere un segno meno:

^\D+(-?\d+).*

62
Non dimenticare di riutilizzare l'oggetto Patter. La compilazione del picchiettio richiede molto tempo.
— Rastislav Komara,

14
Concordato. Di solito definirei il pattern come un finale statico privato Pattern PATTERN = Pattern.compile ("..."); Ma sono solo io.
— Allain Lalonde,

6
possiamo semplicemente usare Pattern p = Pattern.compile ("\\ d +");
— javaMan,

15
Senza spiegazione questa è una risposta scadente.
— Martin Spamer,

Puoi anche riutilizzare il Matcher. Chiama il metodo reset () del Matcher tra ogni utilizzo. Se condividi il matcher su più thread simultanei, devi sincronizzare l'operazione.
— Marquez,

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

public class Regex1 {
    public static void main(String[]args) {
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher("hello1234goodboy789very2345");
        while(m.find()) {
            System.out.println(m.group());
        }
    }
}

Produzione:

1234
789
2345

La domanda richiede specificamente solo la PRIMA occorrenza di numeri.
— NoBrainer,

34

Allain ha praticamente il codice java, quindi puoi usarlo. Tuttavia, la sua espressione corrisponde solo se i tuoi numeri sono preceduti solo da un flusso di caratteri di parole.

"(\\d+)"

dovrebbe essere in grado di trovare la prima stringa di cifre. Non è necessario specificare cosa c'è prima, se sei sicuro che sarà la prima serie di cifre. Allo stesso modo, è inutile specificare cosa c'è dopo, a meno che non lo si desideri. Se vuoi solo il numero e sei sicuro che sarà la prima stringa di una o più cifre, allora è tutto ciò di cui hai bisogno.

Se ti aspetti che sia sfalsato di spazi, lo renderai ancora più distinto da specificare

"\\s+(\\d+)\\s+"

potrebbe essere migliore.

Se hai bisogno di tutte e tre le parti, questo farà:

"(\\D+)(\\d+)(.*)"

MODIFICA Le espressioni fornite da Allain e Jack suggeriscono che è necessario specificare alcuni sottoinsiemi di non cifre per acquisire cifre . Se dici al motore regex che stai cercando \d, ignorerà tutto prima delle cifre. Se l'espressione di J o A si adatta al modello, l'intera corrispondenza è uguale alla stringa di input . E non c'è motivo di specificarlo. Probabilmente rallenta una partita pulita, se non viene totalmente ignorato.


puoi testare l'ipotesi di Axemans eseguendo un test di esempio e controllando le prestazioni della sua soluzione vs. A / J.
— anjanb,

Non è necessario specificare l'inizio e la fine della stringa. Altrimenti cose come 124xxx123xxx sarebbero abbinate anche se non si adattava alla sua sintassi? O sono ^ e $ impliciti?
— Allain Lalonde,

Allain, anche il tuo fallirebbe. Tu e Jack assumete che i caratteri non digitati precederanno le cifre. O lo fanno o no. In tal caso, nessuna di queste espressioni analizzerà questa riga. Ripeto che, come specificato , il modello per le cifre è sufficiente.
— Axeman,

11

Oltre a Pattern , la classe String di Java ha anche diversi metodi che possono funzionare con espressioni regolari, nel tuo caso il codice sarà:

"ab123abc".replaceFirst("\\D*(\\d*).*", "$1")

dove \\Dè un carattere non cifra.


10

In Java 1.4 e versioni successive:

String input = "...";
Matcher matcher = Pattern.compile("[^0-9]+([0-9]+)[^0-9]+").matcher(input);
if (matcher.find()) {
    String someNumberStr = matcher.group(1);
    // if you need this to be an int:
    int someNumberInt = Integer.parseInt(someNumberStr);
}

8

Questa funzione raccoglie tutte le sequenze corrispondenti dalla stringa. In questo esempio prende tutti gli indirizzi e-mail dalla stringa.

static final String EMAIL_PATTERN = "[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
        + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})";

public List<String> getAllEmails(String message) {      
    List<String> result = null;
    Matcher matcher = Pattern.compile(EMAIL_PATTERN).matcher(message);

    if (matcher.find()) {
        result = new ArrayList<String>();
        result.add(matcher.group());

        while (matcher.find()) {
            result.add(matcher.group());
        }
    }

    return result;
}

Perché message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"creerà un elenco di 3 elementi.


3

Prova a fare qualcosa del genere:

Pattern p = Pattern.compile("^.+(\\d+).+");
Matcher m = p.matcher("Testing123Testing");

if (m.find()) {
    System.out.println(m.group(1));
}

3
-1. Poiché .+consuma avidamente i personaggi, \d+cattura solo il "3"da "123". Inoltre, all'interno dei valori letterali delle stringhe, è necessario evitare la barra rovesciata (l'esempio non verrà compilato).
— Bart Kiers,

3

Soluzione semplice

// Regexplanation:
// ^       beginning of line
// \\D+    1+ non-digit characters
// (\\d+)  1+ digit characters in a capture group
// .*      0+ any character
String regexStr = "^\\D+(\\d+).*";

// Compile the regex String into a Pattern
Pattern p = Pattern.compile(regexStr);

// Create a matcher with the input String
Matcher m = p.matcher(inputStr);

// If we find a match
if (m.find()) {
    // Get the String from the first capture group
    String someDigits = m.group(1);
    // ...do something with someDigits
}

Soluzione in una classe di utensili

public class MyUtil {
    private static Pattern pattern = Pattern.compile("^\\D+(\\d+).*");
    private static Matcher matcher = pattern.matcher("");

    // Assumptions: inputStr is a non-null String
    public static String extractFirstNumber(String inputStr){
        // Reset the matcher with a new input String
        matcher.reset(inputStr);

        // Check if there's a match
        if(matcher.find()){
            // Return the number (in the first capture group)
            return matcher.group(1);
        }else{
            // Return some default value, if there is no match
            return null;
        }
    }
}

...

// Use the util function and print out the result
String firstNum = MyUtil.extractFirstNumber("Testing4234Things");
System.out.println(firstNum);

1

Guarda, puoi farlo usando StringTokenizer

String str = "as:"+123+"as:"+234+"as:"+345;
StringTokenizer st = new StringTokenizer(str,"as:");

while(st.hasMoreTokens())
{
  String k = st.nextToken();    // you will get first numeric data i.e 123
  int kk = Integer.parseInt(k);
  System.out.println("k string token in integer        " + kk);

  String k1 = st.nextToken();   //  you will get second numeric data i.e 234
  int kk1 = Integer.parseInt(k1);
  System.out.println("new string k1 token in integer   :" + kk1);

  String k2 = st.nextToken();   //  you will get third numeric data i.e 345
  int kk2 = Integer.parseInt(k2);
  System.out.println("k2 string token is in integer   : " + kk2);
}

Dato che stiamo portando questi dati numerici in tre diverse variabili, possiamo usare questi dati ovunque nel codice (per ulteriore uso)


0

Che [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*ne pensi penso che si occuperebbe dei numeri con una parte frazionaria. Ho incluso spazi bianchi e incluso ,come possibile separatore. Sto cercando di ottenere i numeri da una stringa compresi i float e tenendo conto che l'utente potrebbe fare un errore e includere spazi bianchi durante la digitazione del numero.


0

A volte puoi usare il semplice metodo .split ("REGEXP") disponibile in java.lang.String. Per esempio:

String input = "first,second,third";

//To retrieve 'first' 
input.split(",")[0] 
//second
input.split(",")[1]
//third
input.split(",")[2]

0
Pattern p = Pattern.compile("(\\D+)(\\d+)(.*)");
Matcher m = p.matcher("this is your number:1234 thank you");
if (m.find()) {
    String someNumberStr = m.group(2);
    int someNumberInt = Integer.parseInt(someNumberStr);
}

1
Modifica con ulteriori informazioni. Le risposte di solo codice e "prova questo" sono scoraggiate, perché non contengono contenuti ricercabili e non spiegano perché qualcuno dovrebbe "provare questo". Facciamo uno sforzo qui per essere una risorsa per la conoscenza.
— Brian Tompsett - 莱恩 莱恩

1
Votazione per la sola ripetizione delle risposte corrette che sono state date molto tempo fa senza aggiungere alcun valore aggiuntivo
— Foraggio

-1

se stai leggendo da un file, questo può aiutarti

              try{
             InputStream inputStream = (InputStream) mnpMainBean.getUploadedBulk().getInputStream();
             BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
             String line;
             //Ref:03
             while ((line = br.readLine()) != null) {
                if (line.matches("[A-Z],\\d,(\\d*,){2}(\\s*\\d*\\|\\d*:)+")) {
                     String[] splitRecord = line.split(",");
                     //do something
                 }
                 else{
                     br.close();
                     //error
                     return;
                 }
             }
                br.close();

             }
         }
         catch (IOException  ioExpception){
             logger.logDebug("Exception " + ioExpception.getStackTrace());
         }
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.