Java-Regex zum Extrahieren von Text zwischen Tags

82

Ich habe eine Datei mit einigen benutzerdefinierten Tags und möchte einen regulären Ausdruck schreiben, um die Zeichenfolge zwischen den Tags zu extrahieren. Zum Beispiel, wenn mein Tag ist:

[customtag]String I want to extract[/customtag]

Wie würde ich einen regulären Ausdruck schreiben, um nur die Zeichenfolge zwischen den Tags zu extrahieren? Dieser Code scheint ein Schritt in die richtige Richtung zu sein:

Pattern p = Pattern.compile("[customtag](.+?)[/customtag]");
Matcher m = p.matcher("[customtag]String I want to extract[/customtag]");

Ich bin mir nicht sicher, was ich als nächstes tun soll. Irgendwelche Ideen? Vielen Dank.

b10hazard
quelle
1
Für den Anfang müssen Sie die []eckigen Klammern, die Metazeichen in einem regulären Ausdruck sind, entfernen.
Ridgerunner

Antworten:

183

Du bist auf dem richtigen Weg. Jetzt müssen Sie nur noch die gewünschte Gruppe wie folgt extrahieren:

final Pattern pattern = Pattern.compile("<tag>(.+?)</tag>", Pattern.DOTALL);
final Matcher matcher = pattern.matcher("<tag>String I want to extract</tag>");
matcher.find();
System.out.println(matcher.group(1)); // Prints String I want to extract

Wenn Sie mehrere Treffer extrahieren möchten, versuchen Sie Folgendes:

public static void main(String[] args) {
    final String str = "<tag>apple</tag><b>hello</b><tag>orange</tag><tag>pear</tag>";
    System.out.println(Arrays.toString(getTagValues(str).toArray())); // Prints [apple, orange, pear]
}

private static final Pattern TAG_REGEX = Pattern.compile("<tag>(.+?)</tag>", Pattern.DOTALL);

private static List<String> getTagValues(final String str) {
    final List<String> tagValues = new ArrayList<String>();
    final Matcher matcher = TAG_REGEX.matcher(str);
    while (matcher.find()) {
        tagValues.add(matcher.group(1));
    }
    return tagValues;
}

Ich stimme jedoch zu, dass reguläre Ausdrücke hier nicht die beste Antwort sind. Ich würde XPath verwenden, um Elemente zu finden, die mich interessieren. Weitere Informationen finden Sie in der Java XPath-API .

hoipolloi
quelle
3
Vielen Dank, das ist genau das, was ich brauchte. Ich werde mich mit XPaths befassen, aber im Moment denke ich, dass diese Lösung funktionieren wird. Meine Bewerbungen sind sehr einfach und werden es wahrscheinlich auch bleiben. Danke noch einmal!
b10hazard
Was ist mit dieser Saite "<tag>apple</tag><b>hello</b><tag>orange</tag><tag>pear"? Wie können wir pearohne Close Tag kommen?
K.Sopheak
Um zu verallgemeinern: private String extractDataFromTags (String tag) {Pattern pattern = Pattern.compile ("<. +?> (. +?) </.+?>"); Matcher matcher = pattern.matcher (tag); matcher.find (); return (matcher.group (1)); // Druckt einen String, den ich extrahieren möchte, oder
löst eine
15

Um ganz ehrlich zu sein, sind reguläre Ausdrücke nicht die beste Idee für diese Art der Analyse. Der reguläre Ausdruck, den Sie gepostet haben, eignet sich wahrscheinlich hervorragend für einfache Fälle. Wenn die Dinge jedoch komplexer werden, treten große Probleme auf (der gleiche Grund, warum Sie HTML nicht zuverlässig mit regulären Ausdrücken analysieren können). Ich weiß, dass Sie das wahrscheinlich nicht hören möchten. Ich weiß, dass ich es nicht getan habe, als ich die gleiche Art von Fragen gestellt habe, aber das Parsen von Zeichenfolgen wurde für mich viel zuverlässiger, nachdem ich aufgehört hatte, für alles reguläre Ausdrücke zu verwenden.

jTopas ist ein FANTASTISCHER Tokenizer, der es ziemlich einfach macht, Parser von Hand zu schreiben (ich empfehle dringend Jtopas gegenüber den Standard-Java-Scanner / etc .. -Bibliotheken). Wenn Sie in Aktion sehen jtopas wollen, hier sind einige Parser ich mit jTopas schrieb analysieren diese Art von Datei

Wenn Sie XML-Dateien analysieren, sollten Sie eine XML-Parser-Bibliothek verwenden. Tun Sie es nicht selbst, es sei denn, Sie machen es nur zum Spaß, es gibt viele bewährte Optionen

jdc0589
quelle
Danke für den Vorschlag. Ich habe sie mit einem Lesezeichen versehen und werde dies sicherlich in zukünftigen Projekten prüfen. Im Moment ist die Regex-Methode wahrscheinlich die, mit der ich arbeiten werde, da die Datei, die ich analysiere, sehr klein / einfach ist.
b10hazard
7

Ein generischer, einfacher und etwas primitiver Ansatz zum Finden von Tags, Attributen und Werten

    Pattern pattern = Pattern.compile("<(\\w+)( +.+)*>((.*))</\\1>");
    System.out.println(pattern.matcher("<asd> TEST</asd>").find());
    System.out.println(pattern.matcher("<asd TEST</asd>").find());
    System.out.println(pattern.matcher("<asd attr='3'> TEST</asd>").find());
    System.out.println(pattern.matcher("<asd> <x>TEST<x>asd>").find());
    System.out.println("-------");
    Matcher matcher = pattern.matcher("<as x> TEST</as>");
    if (matcher.find()) {
        for (int i = 0; i <= matcher.groupCount(); i++) {
            System.out.println(i + ":" + matcher.group(i));
        }
    }
Gorki
quelle
Was wäre das Muster, wenn es eine Folge von verschiedenen Tags oder verschachtelten Tags wie <h2>Mac</h2><h1>loves it</h1>oder gibt <h2>Mac<h1>liked your answer</h1></h2>?
MAC
1
Bitte bearbeiten Sie i <matcher.groupCount (); zu i <= matcher.groupCount (); um den ersten passenden Teilstring einzuschließen, dh. am 0. Index
AVA
4

Versuche dies:

Pattern p = Pattern.compile(?<=\\<(any_tag)\\>)(\\s*.*\\s*)(?=\\<\\/(any_tag)\\>);
Matcher m = p.matcher(anyString);

Zum Beispiel:

String str = "<TR> <TD>1Q Ene</TD> <TD>3.08%</TD> </TR>";
Pattern p = Pattern.compile("(?<=\\<TD\\>)(\\s*.*\\s*)(?=\\<\\/TD\\>)");
Matcher m = p.matcher(str);
while(m.find()){
   Log.e("Regex"," Regex result: " + m.group())       
}

Ausgabe:

10 Ene

3,08%

Heriberto Rivera
quelle
2
    final Pattern pattern = Pattern.compile("tag\\](.+?)\\[/tag");
    final Matcher matcher = pattern.matcher("[tag]String I want to extract[/tag]");
    matcher.find();
    System.out.println(matcher.group(1));
Bibhuti Agarwal
quelle
Wie wäre es mit Präfix für Tag (wenn Präfix dynamisch ist)
user1514499
2
    String s = "<B><G>Test</G></B><C>Test1</C>";

    String pattern ="\\<(.+)\\>([^\\<\\>]+)\\<\\/\\1\\>";

       int count = 0;

        Pattern p = Pattern.compile(pattern);
        Matcher m =  p.matcher(s);
        while(m.find())
        {
            System.out.println(m.group(2));
            count++;
        }
Shubham Khurana
quelle
1

Ich stelle dieser Antwort "Sie sollten keinen regulären Ausdruck zum Parsen von XML verwenden - dies führt nur zu Randfällen, die nicht richtig funktionieren, und zu einem immer komplexer werdenden regulären Ausdruck, während Sie versuchen, das Problem zu beheben." . "

Davon abgesehen müssen Sie fortfahren, indem Sie die Zeichenfolge abgleichen und die gewünschte Gruppe auswählen:

if (m.matches())
{
   String result = m.group(1);
   // do something with result
}
Shirik
quelle