Utilisation de Java pour trouver une sous-chaîne d'une chaîne plus grande à l'aide d'une expression régulière

140

Si j'ai une chaîne comme celle-ci:

FOO[BAR]

J'ai besoin d'un moyen générique pour extraire la chaîne "BAR" de la chaîne afin que peu importe la chaîne entre les crochets, elle puisse obtenir la chaîne.

par exemple

FOO[DOG] = DOG
FOO[CAT] = CAT
digiarnie
la source

Réponses:

253

Vous devriez pouvoir utiliser des quantificateurs non gourmands, en particulier * ?. Vous allez probablement vouloir ce qui suit:

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

Cela vous donnera un modèle qui correspondra à votre chaîne et mettra le texte entre crochets dans le premier groupe. Consultez la documentation de l'API Pattern pour plus d'informations.

Pour extraire la chaîne, vous pouvez utiliser quelque chose comme ce qui suit:

Matcher m = MY_PATTERN.matcher("FOO[BAR]");
while (m.find()) {
    String s = m.group(1);
    // s now contains "BAR"
}
Bryan Kyle
la source
16
Il convient de mentionner que s'il y a une nouvelle ligne entre les crochets, cela échouera et vous devriez utiliser l'indicateur Pattern.DOTALL pour éviter cela.
cletus
En utilisant le modèle ci-dessus, comment utiliseriez-vous alors cela pour extraire la chaîne contenant la chaîne BAR? Je regarde l'API Pattern et l'API Matcher mais je ne sais toujours pas comment obtenir la chaîne elle-même.
digiarnie
@cletus: Bon appel! @digiarnie: J'ai ajouté une révision à la réponse qui contient du code d'homme de paille pour obtenir la correspondance.
Bryan Kyle
30

la manière non-regex:

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

alternativement, pour une meilleure performance / utilisation de la mémoire (merci Hosam):

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf('['),input.lastIndexOf(']'));
zaczap
la source
1
J'utiliserais à la lastIndexOf(']')place, qui gérerait les crochets imbriqués. De plus, je pense que l'utilisation du indexOf(char)serait plus rapide que indexOf(String).
Hosam Aly
De rien. Votre note sur les performances est également très pertinente, car il lastIndexOfsera certainement plus rapide de trouver la parenthèse de fermeture.
Hosam Aly
3
qu'est-ce qui est plus rapide, index de sous-chaîne, etc. ou expression régulière?
Toskan
2
voir la valeur d'Amit pour "extrait" ci-dessous: input.indexOf ('[') + 1
gcbound
28

Voici un exemple de travail:

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

Il affiche :

value1
value2
value3
Djahid Bekka
la source
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
la source
5

Si vous avez simplement besoin d'obtenir ce qui se trouve entre les deux [], vous pouvez utiliser \[([^\]]*)\]comme ceci:

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

Si vous en avez besoin de la forme, identifier + [ + content + ]vous pouvez limiter l'extraction du contenu uniquement lorsque l'identifiant est un alphanumérique:

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

Cela validera des choses comme Foo [Bar], ou myDevice_123["input"]par exemple.

Problème principal

Le problème principal est lorsque vous souhaitez extraire le contenu de quelque chose comme ceci:

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

Le Regex ne fonctionnera pas et reviendra BAR[CAT[123et FOO.
Si nous changeons l'expression régulière en \[(.*)\]alors tout va bien, mais si vous essayez d'extraire le contenu de choses plus complexes comme:

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

Aucun des Regex ne fonctionnera.

Le Regex le plus précis pour extraire le contenu approprié dans tous les cas serait beaucoup plus complexe car il faudrait équilibrer les []paires et vous donner leur contenu.

Une solution plus simple

Si vos problèmes deviennent complexes et que le contenu est []arbitraire, vous pouvez à la place équilibrer les paires de []et extraire la chaîne en utilisant un ancien code plutôt qu'un 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;
}   

C'est plus du pseudo-code que du vrai code, je ne suis pas un codeur Java donc je ne sais pas si la syntaxe est correcte, mais cela devrait être assez facile à améliorer.
Ce qui compte, c'est que ce code doit fonctionner et vous permettre d'extraire le contenu du [], aussi complexe soit-il.

Renaud Bompuis
la source
2

Je pense que votre expression régulière ressemblerait à:

/FOO\[(.+)\]/

En supposant que FOO va être constant.

Donc, pour mettre cela en Java:

Pattern p = Pattern.compile("FOO\\[(.+)\\]");
Matcher m = p.matcher(inputLine);
Kevin Lacquement
la source
FOO [BAR] FOO [BAZ] -> avec votre regex retournera: "BAR] FOO [BAZ"
Mohammad Jafar Mashhadi
1
String input = "FOO[BAR]";
String result = input.substring(input.indexOf("[")+1,input.lastIndexOf("]"));

Cela renverra la valeur entre le premier '[' et le dernier ']'

Foo [Bar] => Bar

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

Remarque: vous devez ajouter une vérification d'erreur si la chaîne d'entrée n'est pas bien formée.

amit
la source
0

en supposant qu'aucun autre crochet fermant n'est autorisé à l'intérieur, / FOO \ [([^ \]] *) \] /

Manu
la source
0

Je définirais que je veux un nombre maximum de caractères non-] entre [et ]. Ceux-ci doivent être échappés avec des barres obliques inverses (et en Java, ils doivent être échappés à nouveau), et la définition de non-] est une classe de caractères, donc à l'intérieur de [et ](ie [^\\]]). Le résultat:

FOO\\[([^\\]]+)\\]
Fabian Steeg
la source
0

Comme ça, son travail si vous voulez analyser une chaîne qui provient de mYearInDB.toString () = [2013] cela donnera 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);

la source
0

Cette expression rationnelle fonctionne pour moi:

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

exemple:

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

production:

Match 1
1.  company_details
Match 2
1.  company_details

Testé sur http://rubular.com/

rusllonrails
la source
0
"FOO[DOG]".replaceAll("^.*?\\[|\\].*", "");

Cela renverra une chaîne ne prenant que la chaîne entre crochets.

Cela supprime toutes les chaînes en dehors des crochets.

Vous pouvez tester cet exemple de code java en ligne: http://tpcg.io/wZoFu0

Vous pouvez tester cette expression régulière à partir d'ici: https://regex101.com/r/oUAzsS/1

Jorge Wander Santana Ureña
la source