Używanie języka Java do znajdowania podłańcucha większego ciągu za pomocą wyrażenia regularnego

140

Jeśli mam taki ciąg:

FOO[BAR]

Potrzebuję ogólnego sposobu, aby uzyskać ciąg „BAR” z ciągu, tak aby bez względu na to, jaki ciąg znajduje się między nawiasami kwadratowymi, byłby w stanie uzyskać ciąg.

na przykład

FOO[DOG] = DOG
FOO[CAT] = CAT
digiarnie
źródło

Odpowiedzi:

253

Powinieneś móc używać niechciwych kwantyfikatorów, a konkretnie * ?. Prawdopodobnie będziesz potrzebować następujących rzeczy:

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

To da ci wzór, który będzie pasował do twojego ciągu i umieści tekst w nawiasach kwadratowych w pierwszej grupie. Zapoznaj się z dokumentacją Pattern API, aby uzyskać więcej informacji.

Aby wyodrębnić ciąg, możesz użyć czegoś takiego:

Matcher m = MY_PATTERN.matcher("FOO[BAR]");
while (m.find()) {
    String s = m.group(1);
    // s now contains "BAR"
}
Bryan Kyle
źródło
16
Warto wspomnieć, że jeśli między nawiasami kwadratowymi znajduje się nowa linia, zakończy się to niepowodzeniem i aby tego uniknąć, należy użyć flagi Pattern.DOTALL.
cletus
Korzystając z powyższego wzorca, w jaki sposób użyłbyś tego do wyodrębnienia ciągu zawierającego ciąg BAR? Patrzę na API Pattern i Matcher API, ale nadal nie jestem pewien, jak uzyskać sam ciąg.
digiarnie
@cletus: Dobre połączenie! @digiarnie: Dodałem poprawkę do odpowiedzi, która zawiera kod słomkowy do uzyskania dopasowania.
Bryan Kyle
30

sposób bez wyrażeń regularnych:

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

alternatywnie, dla nieco lepszej wydajności / wykorzystania pamięci (dzięki Hosam):

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf('['),input.lastIndexOf(']'));
zaczap
źródło
1
Chciałbym używać lastIndexOf(']')zamiast, który będzie obsługiwać nawiasów zagnieżdżonych. Ponadto uważam, że użycie programu indexOf(char)byłoby szybsze niż indexOf(String).
Hosam Aly
Nie ma za co. Twoja uwaga na temat wydajności jest również bardzo istotna, ponieważ lastIndexOfz pewnością szybciej będzie znaleźć nawias zamykający.
Hosam Aly
3
co jest szybsze, indeksowanie podciągów itp. itp. czy wyrażenie regularne?
Toskan
2
zobacz wartość Amita dla „wyodrębnionego” poniżej: input.indexOf ('[') + 1
gcbound
28

Oto działający przykład:

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

To pokazuje :

value1
value2
value3
Djahid Bekka
źródło
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
źródło
5

Jeśli po prostu potrzebujesz zdobyć to, co jest pomiędzy [], możesz użyć w \[([^\]]*)\]następujący sposób:

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

Jeśli chcesz, aby był w formie identifier + [ + content + ], możesz ograniczyć wyodrębnianie treści tylko wtedy, gdy identyfikator jest alfanumeryczny:

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

Pozwoli to zweryfikować takie rzeczy Foo [Bar], albo myDevice_123["input"]na przykład.

Główna kwestia

Główny problem występuje, gdy chcesz wyodrębnić zawartość czegoś takiego:

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

Regex nie będzie działać i wróci BAR[CAT[123i FOO.
Jeśli zmienimy Regex na, \[(.*)\]wszystko jest w porządku, ale jeśli próbujesz wyodrębnić zawartość z bardziej złożonych rzeczy, takich jak:

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

Żaden z Regexów nie zadziała.

Najdokładniejszy Regex do wyodrębnienia właściwej treści we wszystkich przypadkach byłby znacznie bardziej złożony, ponieważ musiałby zrównoważyć []pary i zapewnić ich zawartość.

Prostsze rozwiązanie

Jeśli twoje problemy stają się coraz bardziej złożone, a zawartość jest []arbitralna, możesz zamiast tego zrównoważyć pary []i wyodrębnić ciąg przy użyciu zwykłego starego kodu zamiast Regex:

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

To jest bardziej pseudokod niż prawdziwy kod, nie jestem koderem Java, więc nie wiem, czy składnia jest poprawna, ale powinno być wystarczająco łatwe do ulepszenia.
Liczy się to, że ten kod powinien działać i pozwalać na wyodrębnienie zawartości [], jakkolwiek jest to skomplikowane.

Renaud Bompuis
źródło
2

Myślę, że twoje wyrażenie regularne wyglądałoby tak:

/FOO\[(.+)\]/

Zakładając, że inspektor obsługi lotów będzie stały.

Tak więc, aby umieścić to w Javie:

Pattern p = Pattern.compile("FOO\\[(.+)\\]");
Matcher m = p.matcher(inputLine);
Kevin Lacquement
źródło
FOO [BAR] FOO [BAZ] -> z Twoim wyrażeniem regularnym powróci: „BAR] FOO [BAZ”
Mohammad Jafar Mashhadi
1
String input = "FOO[BAR]";
String result = input.substring(input.indexOf("[")+1,input.lastIndexOf("]"));

To zwróci wartość między pierwszym „[” a ostatnim „]”

Foo [Bar] => Bar

Foo [Bar [test]] => Bar [test]

Uwaga: należy dodać funkcję sprawdzania błędów, jeśli ciąg wejściowy nie jest poprawnie sformułowany.

dobrze
źródło
0

zakładając, że żaden inny zamykający nawias kwadratowy nie jest dozwolony w obrębie, / FOO \ [([^ \]] *) \] /

Manu
źródło
0

Zdefiniowałbym, że chcę mieć maksymalną liczbę znaków innych niż] między [a ]. Muszą być one poprzedzone odwrotnym ukośnikiem (aw Javie trzeba je ponownie zmienić), a definicja non-] jest klasą znaków, a więc wewnątrz [i ](tj [^\\]].). Wynik:

FOO\\[([^\\]]+)\\]
Fabian Steeg
źródło
0

W ten sposób jego praca, jeśli chcesz przeanalizować jakiś ciąg, który pochodzi z mYearInDB.toString () = [2013], da 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);

źródło
0

To wyrażenie regularne działa dla mnie:

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

przykład:

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

wynik:

Match 1
1.  company_details
Match 2
1.  company_details

Przetestowano na http://rubular.com/

rusllonrails
źródło
0
"FOO[DOG]".replaceAll("^.*?\\[|\\].*", "");

Spowoduje to zwrócenie łańcucha zawierającego tylko ciąg w nawiasach kwadratowych.

Spowoduje to usunięcie całego ciągu na zewnątrz z nawiasów kwadratowych.

Możesz przetestować ten przykładowy kod java online: http://tpcg.io/wZoFu0

Możesz przetestować to wyrażenie regularne tutaj: https://regex101.com/r/oUAzsS/1

Jorge Wander Santana Ureña
źródło