Verwenden von Java zum Suchen der Teilzeichenfolge einer größeren Zeichenfolge mithilfe des regulären Ausdrucks

140

Wenn ich eine Zeichenfolge wie diese habe:

FOO[BAR]

Ich brauche eine generische Methode, um die Zeichenfolge "BAR" aus der Zeichenfolge herauszuholen, damit die Zeichenfolge unabhängig von der Zeichenfolge in den eckigen Klammern abgerufen werden kann.

z.B

FOO[DOG] = DOG
FOO[CAT] = CAT
digiarnie
quelle

Antworten:

253

Sie sollten in der Lage sein, nicht gierige Quantifizierer zu verwenden, insbesondere *?. Sie werden wahrscheinlich Folgendes wollen:

Pattern MY_PATTERN = Pattern.compile("\\[(.*?)\\]");

Dadurch erhalten Sie ein Muster, das zu Ihrer Zeichenfolge passt, und setzen den Text in die eckigen Klammern der ersten Gruppe. Weitere Informationen finden Sie in der Muster-API-Dokumentation .

Um die Zeichenfolge zu extrahieren, können Sie Folgendes verwenden:

Matcher m = MY_PATTERN.matcher("FOO[BAR]");
while (m.find()) {
    String s = m.group(1);
    // s now contains "BAR"
}
Bryan Kyle
quelle
16
Es ist erwähnenswert, dass ein Zeilenumbruch zwischen den eckigen Klammern fehlschlägt und Sie das Flag Pattern.DOTALL verwenden sollten, um dies zu vermeiden.
Cletus
Wie würden Sie dann mit dem obigen Muster die Zeichenfolge extrahieren, die die Zeichenfolge BAR enthält? Ich sehe mir die Pattern-API und die Matcher-API an, bin mir aber immer noch nicht sicher, wie ich die Zeichenfolge selbst erhalten soll.
Digiarnie
@cletus: Guter Anruf! @digiarnie: Ich habe der Antwort eine Überarbeitung hinzugefügt, die einen Strohmann-Code enthält, um das Match zu erhalten.
Bryan Kyle
30

der nicht-reguläre Weg:

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf("["),input.indexOf("]"));

alternativ für etwas bessere Leistung / Speichernutzung (danke Hosam):

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf('['),input.lastIndexOf(']'));
zaczap
quelle
1
Ich würde lastIndexOf(']')stattdessen verwenden, was verschachtelte Klammern behandeln würde. Darüber hinaus glaube ich, dass die Verwendung der indexOf(char)schneller wäre als indexOf(String).
Hosam Aly
Bitte. Ihr Hinweis zur Leistung ist ebenfalls sehr relevant, da lastIndexOfdas Schließen der schließenden Klammer sicherlich schneller sein wird.
Hosam Aly
3
Was ist schneller, Index von Teilzeichenfolgen usw. usw. oder regulärer Ausdruck?
Toskan
2
siehe Amits Wert für "extrahiert" unten: input.indexOf ('[') + 1
gcbound
28

Dies ist ein funktionierendes Beispiel:

RegexpExample.java

package org.regexp.replace;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexpExample
{
    public static void main(String[] args)
    {
        String string = "var1[value1], var2[value2], var3[value3]";
        Pattern pattern = Pattern.compile("(\\[)(.*?)(\\])");
        Matcher matcher = pattern.matcher(string);

        List<String> listMatches = new ArrayList<String>();

        while(matcher.find())
        {
            listMatches.add(matcher.group(2));
        }

        for(String s : listMatches)
        {
            System.out.println(s);
        }
    }
}

Es zeigt an :

value1
value2
value3
Djahid Bekka
quelle
6
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public static String get_match(String s, String p) {
    // returns first match of p in s for first group in regular expression 
    Matcher m = Pattern.compile(p).matcher(s);
    return m.find() ? m.group(1) : "";
}

get_match("FOO[BAR]", "\\[(.*?)\\]")  // returns "BAR"

public static List<String> get_matches(String s, String p) {
    // returns all matches of p in s for first group in regular expression 
    List<String> matches = new ArrayList<String>();
    Matcher m = Pattern.compile(p).matcher(s);
    while(m.find()) {
        matches.add(m.group(1));
    }
    return matches;
}

get_matches("FOO[BAR] FOO[CAT]", "\\[(.*?)\\]")) // returns [BAR, CAT]
Dansalmo
quelle
5

Wenn Sie nur das bekommen müssen, was dazwischen liegt [], können Sie Folgendes verwenden \[([^\]]*)\]:

Pattern regex = Pattern.compile("\\[([^\\]]*)\\]");
Matcher m = regex.matcher(str);
if (m.find()) {
    result = m.group();
}

Wenn es die Form haben soll identifier + [ + content + ], können Sie das Extrahieren des Inhalts nur einschränken, wenn der Bezeichner eine alphanumerische Zahl ist:

[a-zA-Z][a-z-A-Z0-9_]*\s*\[([^\]]*)\]

Dies wird Dinge wie Foo [Bar]oder myDevice_123["input"]zum Beispiel validieren .

Hauptproblem

Das Hauptproblem ist, wenn Sie den Inhalt von so etwas extrahieren möchten:

FOO[BAR[CAT[123]]+DOG[FOO]]

Der Regex wird nicht funktionieren und wird zurückkehren BAR[CAT[123und FOO.
Wenn wir den Regex in ändern, sind \[(.*)\]wir in Ordnung, aber wenn Sie versuchen, den Inhalt aus komplexeren Dingen zu extrahieren, wie z.

FOO[BAR[CAT[123]]+DOG[FOO]] = myOtherFoo[BAR[5]]

Keiner der Regexes funktioniert.

Der genaueste Regex, um in allen Fällen den richtigen Inhalt zu extrahieren, wäre viel komplexer, da er []Paare ausgleichen und ihnen den Inhalt geben müsste .

Eine einfachere Lösung

Wenn Ihre Probleme komplex werden und der Inhalt []beliebig ist, können Sie stattdessen die Paare von ausgleichen []und die Zeichenfolge mit einem einfachen alten Code als einem Regex extrahieren:

int i;
int brackets = 0;
string c;
result = "";
for (i = input.indexOf("["); i < str.length; i++) {
    c = str.substring(i, i + 1);
    if (c == '[') {
        brackets++;
    } else if (c == ']') {
        brackets--;
        if (brackets <= 0) 
            break;
    }
    result = result + c;
}   

Dies ist mehr Pseudocode als echter Code. Ich bin kein Java-Codierer, daher weiß ich nicht, ob die Syntax korrekt ist, aber es sollte leicht genug sein, sie zu verbessern.
Was zählt ist, dass dieser Code funktionieren sollte und es Ihnen ermöglichen sollte, den Inhalt des noch []so komplexen Codes zu extrahieren .

Renaud Bompuis
quelle
2

Ich denke, Ihr regulärer Ausdruck würde so aussehen:

/FOO\[(.+)\]/

Angenommen, FOO wird konstant sein.

Um dies in Java zu formulieren:

Pattern p = Pattern.compile("FOO\\[(.+)\\]");
Matcher m = p.matcher(inputLine);
Kevin Lacquement
quelle
FOO [BAR] FOO [BAZ] -> mit Ihrer Regex wird zurückkehren: "BAR] FOO [BAZ"
Mohammad Jafar Mashhadi
1
String input = "FOO[BAR]";
String result = input.substring(input.indexOf("[")+1,input.lastIndexOf("]"));

Dies gibt den Wert zwischen dem ersten '[' und dem letzten ']' zurück.

Foo [Bar] => Bar

Foo [Bar [Test]] => Bar [Test]

Hinweis: Sie sollten eine Fehlerprüfung hinzufügen, wenn die Eingabezeichenfolge nicht richtig geformt ist.

amit
quelle
0

unter der Annahme, dass in / FOO \ [([^ \]] *) \] / keine andere schließende eckige Klammer zulässig ist

Manu
quelle
0

Ich würde definieren, dass ich eine maximale Anzahl von Nicht-] Zeichen zwischen [und möchte ]. Diese müssen mit Backslashes maskiert werden (und in Java müssen diese erneut maskiert werden), und die Definition von non-] ist eine Zeichenklasse, also innerhalb [und ](dh [^\\]]). Das Ergebnis:

FOO\\[([^\\]]+)\\]
Fabian Steeg
quelle
0

So funktioniert es, wenn Sie einen String analysieren möchten, der von mYearInDB.toString () = [2013] stammt. Er gibt 2013

Matcher n = MY_PATTERN.matcher("FOO[BAR]"+mYearInDB.toString());
while (n.find()) {
 extracredYear  = n.group(1);
 // s now contains "BAR"
    }
    System.out.println("Extrated output is : "+extracredYear);

quelle
0

Dieser reguläre Ausdruck funktioniert für mich:

form\[([^']*?)\]

Beispiel:

form[company_details][0][name]
form[company_details][0][common_names][1][title]

Ausgabe:

Match 1
1.  company_details
Match 2
1.  company_details

Getestet auf http://rubular.com/

Rusllonrails
quelle
0
"FOO[DOG]".replaceAll("^.*?\\[|\\].*", "");

Dies gibt eine Zeichenfolge zurück, die nur die Zeichenfolge in eckigen Klammern verwendet.

Dadurch werden alle Zeichenfolgen außerhalb der eckigen Klammern entfernt.

Sie können diesen Java-Beispielcode online testen: http://tpcg.io/wZoFu0

Sie können diesen regulären Ausdruck hier testen: https://regex101.com/r/oUAzsS/1

Jorge Wander Santana Ureña
quelle