Verwenden regulärer Ausdrücke zum Extrahieren eines Werts in Java

169

Ich habe mehrere Saiten in der groben Form:

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

Ich möchte den Text in [einer Zahl] mit den Java Regex-Klassen extrahieren.

Ich weiß ungefähr, welchen regulären Ausdruck ich verwenden möchte (obwohl alle Vorschläge willkommen sind). Was mich wirklich interessiert, sind die Java-Aufrufe, die Regex-Zeichenfolge zu verwenden und sie für die Quelldaten zu verwenden, um den Wert von [eine Zahl] zu erzeugen.

EDIT: Ich sollte hinzufügen, dass ich nur an einer einzelnen [einer Nummer] interessiert bin (im Grunde die erste Instanz). Die Quellzeichenfolgen sind kurz und ich werde nicht nach mehreren Vorkommen von [einer bestimmten Anzahl] suchen.

Craig Walker
quelle
11
... und jetzt mache ich mich auf den Weg zur Forschung. Mal sehen, ob SO eine Antwort für mich bekommen kann, bevor ich es selbst herausfinde. :-P
Craig Walker
Dies war eine Interviewfrage bei einem Bank- / Investment- / Handelsunternehmen für Software-Engineering, nicht wahr? : P
8.
@ennth Nein, nicht mal in der Nähe! Es war für Produktionscode auf einer Website für kleine Unternehmen ... vor vielen Monden.
Craig Walker
1
Verdammt gut, mir wurde vor ein paar Tagen bei einer Codierungsprüfung von JP Morgan Chase Software Engineering fast die gleiche Frage gestellt: P
10.

Antworten:

316

Vollständiges Beispiel:

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

Da Sie nach der ersten Nummer suchen, können Sie einen solchen regulären Ausdruck verwenden:

^\D+(\d+).*

und m.group(1)wird Ihnen die erste Nummer zurückgeben. Beachten Sie, dass vorzeichenbehaftete Zahlen ein Minuszeichen enthalten können:

^\D+(-?\d+).*
Allain Lalonde
quelle
62
Vergessen Sie nicht, das Patter-Objekt wiederzuverwenden. Das Kompilieren von Mustern nimmt sehr viel Zeit in Anspruch.
Rastislav Komara
14
Einverstanden. Normalerweise würde ich das Muster als privates statisches endgültiges Muster definieren. PATTERN = Pattern.compile ("..."); Aber das bin nur ich.
Allain Lalonde
6
wir können einfach Pattern p = Pattern.compile ("\\ d +") verwenden;
JavaMan
15
Ohne Erklärung ist dies eine schlechte Antwort.
Martin Spamer
Sie können den Matcher auch wiederverwenden. Rufen Sie zwischen jeder Verwendung die reset () -Methode des Matchers auf. Wenn Sie den Matcher für mehrere gleichzeitige Threads freigeben, sollten Sie den Vorgang synchronisieren.
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());
        }
    }
}

Ausgabe:

1234
789
2345
javaMan
quelle
Die Frage fragt speziell nur nach dem ERSTEN Auftreten von Zahlen.
NoBrainer
34

Allain hat im Grunde den Java-Code, also können Sie diesen verwenden. Sein Ausdruck stimmt jedoch nur überein, wenn Ihren Zahlen nur ein Strom von Wortzeichen vorangestellt ist.

"(\\d+)"

sollte in der Lage sein, die erste Ziffernfolge zu finden. Sie müssen nicht angeben, was davor steht, wenn Sie sicher sind, dass es sich um die erste Ziffernfolge handelt. Ebenso kann man nicht angeben, was danach ist, es sei denn, Sie möchten das. Wenn Sie nur die Nummer möchten und sicher sind, dass es sich um die erste Zeichenfolge mit einer oder mehreren Ziffern handelt, ist dies alles, was Sie benötigen.

Wenn Sie erwarten, dass es durch Leerzeichen versetzt wird, wird die Angabe noch deutlicher

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

könnte besser sein.

Wenn Sie alle drei Teile benötigen, reicht dies aus:

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

EDIT Die Ausdrücke von Allain und Jack lassen vermuten , dass Sie eine gewisse Teilmenge von Nicht-Ziffern zu erfassen , um spezifizieren müssen Ziffern . Wenn Sie der Regex-Engine mitteilen, nach der Sie suchen \d, wird alles vor den Ziffern ignoriert. Wenn J oder A Ausdruck paßt Ihr Muster, dann das ganze Spiel ist gleich die Eingabezeichenfolge . Und es gibt keinen Grund, dies anzugeben. Es verlangsamt wahrscheinlich ein sauberes Match, wenn es nicht völlig ignoriert wird.

Axeman
quelle
Sie können die Hypothese von Axemans testen, indem Sie einen Beispieltest durchführen und die Leistung seiner vs. A / J-Lösung überprüfen.
Anjanb
Sie müssen nicht den Anfang und das Ende der Zeichenfolge angeben. Andernfalls würden Dinge wie 124xxx123xxx übereinstimmen, obwohl es nicht in seine Syntax passt? Oder sind ^ und $ implizit?
Allain Lalonde
Allain, deine würde auch scheitern. Sie und Jack gehen davon aus, dass nichtstellige Zeichen vor den Ziffern stehen. Sie tun es entweder oder sie tun es nicht. In diesem Fall analysiert keiner dieser Ausdrücke diese Zeile. Ich wiederhole, dass das Muster für die Ziffern wie angegeben ausreicht.
Axeman
11

Zusätzlich zu Pattern verfügt die Java String- Klasse über mehrere Methoden, die mit regulären Ausdrücken arbeiten können. In Ihrem Fall lautet der Code:

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

wo \\Dist ein nichtstelliges Zeichen.

Vitalii Fedorenko
quelle
10

In Java 1.4 und höher:

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);
}
Jack Leow
quelle
8

Diese Funktion sammelt alle übereinstimmenden Sequenzen aus der Zeichenfolge. In diesem Beispiel werden alle E-Mail-Adressen aus der Zeichenfolge übernommen.

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

Denn message = "[email protected], <[email protected]>>>> [email protected]"es wird eine Liste von 3 Elementen erstellt.

LukaszTaraszka
quelle
3

Versuchen Sie so etwas zu tun:

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

if (m.find()) {
    System.out.println(m.group(1));
}
Farbton Naing Win
quelle
3
-1. Da .+gierig Zeichen verbraucht, \d+erfasst nur das "3"von "123". Außerdem müssen Sie in String-Literalen den Backslash umgehen (Ihr Beispiel wird nicht kompiliert).
Bart Kiers
3

Einfache Lösung

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

Lösung in einer Util-Klasse

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);
Klacks
quelle
1

Schauen Sie, Sie können es mit StringTokenizer tun

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

Da wir diese numerischen Daten in drei verschiedene Variablen umwandeln, können wir diese Daten an einer beliebigen Stelle im Code verwenden (zur weiteren Verwendung).

Shounak
quelle
0

Wie [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*wäre es, wenn ich denke, es würde sich um Zahlen mit Bruchteilen kümmern. Ich habe Leerzeichen und ,als mögliches Trennzeichen eingefügt. Ich versuche, die Zahlen aus einer Zeichenfolge einschließlich Floats herauszuholen und zu berücksichtigen, dass der Benutzer möglicherweise einen Fehler macht und Leerzeichen einfügt, während er die Zahl eingibt.

Arturo
quelle
0

Manchmal können Sie die einfache .split-Methode ("REGEXP") verwenden, die in java.lang.String verfügbar ist. Beispielsweise:

String input = "first,second,third";

//To retrieve 'first' 
input.split(",")[0] 
//second
input.split(",")[1]
//third
input.split(",")[2]
user1722707
quelle
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);
}
Mohammadreza Tavakoli
quelle
1
Bitte bearbeiten Sie mit weiteren Informationen. Nur-Code- und "Versuch dies" -Antworten werden nicht empfohlen, da sie keinen durchsuchbaren Inhalt enthalten und nicht erklären, warum jemand "dies versuchen" sollte. Wir bemühen uns hier, eine Ressource für Wissen zu sein.
Brian Tompsett - 莱恩 莱恩
1
Downvote für die Wiederholung korrekter Antworten, die vor langer Zeit gegeben wurden, ohne zusätzlichen Wert hinzuzufügen
Forage
-1

Wenn Sie aus einer Datei lesen, kann dies hilfreich sein

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