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.