Comment extraire une sous-chaîne à l'aide de regex


382

J'ai une chaîne qui contient deux guillemets simples, le 'caractère. Entre les guillemets simples se trouvent les données que je veux.

Comment puis-je écrire une expression régulière pour extraire "les données que je veux" du texte suivant?

mydata = "some string with 'the data i want' inside";

Réponses:


569

En supposant que vous vouliez la partie entre guillemets simples, utilisez cette expression régulière avec un Matcher:

"'(.*?)'"

Exemple:

String mydata = "some string with 'the data i want' inside";
Pattern pattern = Pattern.compile("'(.*?)'");
Matcher matcher = pattern.matcher(mydata);
if (matcher.find())
{
    System.out.println(matcher.group(1));
}

Résultat:

les données que je veux

12
putain .. j'oublie toujours le modificateur non gourmand :(
Mihai Toader

33
remplacer le «si» par un «moment» lorsque vous vous attendez à plus d'une occurrence
OneWorld

14
gardez à l'esprit que matcher.find () est nécessaire pour que cet exemple de code fonctionne. le fait de ne pas appeler cette méthode entraînera une exception «Aucune correspondance trouvée» lorsque matcher.group (1) est appelé.
rexford

25
Le groupe @mFontoura (0) retournerait la correspondance complète avec l'extérieur ''. le groupe (1) renvoie ce qui est entre les '' sans les '' eux-mêmes.
tagy22

6
@Larry, c'est une réponse tardive, mais? dans ce cas, c'est un modificateur non gourmand, de sorte que, pour this 'is' my 'data' with quotescela, il s'arrêterait tôt et retournerait isau lieu de correspondre à autant de caractères que possible et retournerait is' my 'data, ce qui est le comportement par défaut.
Timekiller

68

Vous n'avez pas besoin de regex pour cela.

Ajoutez apache commons lang à votre projet ( http://commons.apache.org/proper/commons-lang/ ), puis utilisez:

String dataYouWant = StringUtils.substringBetween(mydata, "'");

12
Vous devez prendre en compte la façon dont votre logiciel sera distribué. S'il s'agit d'un démarrage Web, il n'est pas judicieux d'ajouter Apache commons uniquement pour utiliser cette fonctionnalité. Mais peut-être que non. Outre Apache commons a beaucoup plus à offrir. Même difficile, il est bon de connaître l'expression régulière, vous devez être prudent sur le moment de l'utiliser. Regex peut être très difficile à lire, à écrire et à déboguer. Compte tenu de certains contextes, cela pourrait être la meilleure solution.
Beothorn

3
Parfois, StringUtils est déjà là, dans ces cas, cette solution est beaucoup plus propre et lisible.
Gábor Nagy

7
C'est comme acheter une voiture pour parcourir 5 miles (lorsque vous ne voyagez qu'une fois par an).
Prayagupd

Alors que la sous-chaîne recherche une chaîne ou une valeur spécifique, l'expression régulière recherche un format. C'est de plus en plus dynamique. Vous avez besoin d'une expression régulière, si vous recherchez un modèle au lieu d'une valeur spéciale.
burakhan alkan

14
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile(".*'([^']*)'.*");
        String mydata = "some string with 'the data i want' inside";

        Matcher matcher = pattern.matcher(mydata);
        if(matcher.matches()) {
            System.out.println(matcher.group(1));
        }

    }
}

2
System.out.println (matcher.group (0)); <--- Index de base zéro
nclord

4
Non. Le groupe (0) a une signification particulière, les groupes de capture commencent au groupe d'index (1) (c'est-à-dire que le groupe (1) est correct dans la réponse). "Les groupes de capture sont indexés de gauche à droite, en commençant par un. Le groupe zéro indique le motif entier" - Source: docs.oracle.com/javase/8/docs/api/java/util/regex/…
Apriori

12

Il existe un simple revêtement pour cela:

String target = myData.replaceAll("[^']*(?:'(.*?)')?.*", "$1");

En rendant le groupe de correspondance facultatif, cela répond également aux citations non trouvées en retournant un blanc dans ce cas.

Voir la démo en direct .


10

Parce que vous avez également coché Scala, une solution sans regex qui gère facilement plusieurs chaînes entre guillemets:

val text = "some string with 'the data i want' inside 'and even more data'"
text.split("'").zipWithIndex.filter(_._2 % 2 != 0).map(_._1)

res: Array[java.lang.String] = Array(the data i want, and even more data)

4
Solution si lisible, c'est pourquoi les gens aiment scala je crois :)
Prayagupd

3
Pourquoi pas juste .split('\'').get(2)ou quelque chose dans cette mesure en Java? Je pense que vous devrez peut-être obtenir une analyse cérébrale si vous pensez que c'est une solution lisible - il semble que quelqu'un essayait de me faire du golf de code.
ArtOfWarfare

7
String dataIWant = mydata.replaceFirst(".*'(.*?)'.*", "$1");

4

comme en javascript:

mydata.match(/'([^']+)'/)[1]

l'expression rationnelle réelle est: /'([^']+)'/

si vous utilisez le modificateur non gourmand (selon un autre post) c'est comme ça:

mydata.match(/'(.*?)'/)[1]

c'est plus propre.


2

À Scala,

val ticks = "'([^']*)'".r

ticks findFirstIn mydata match {
    case Some(ticks(inside)) => println(inside)
    case _ => println("nothing")
}

for (ticks(inside) <- ticks findAllIn mydata) println(inside) // multiple matches

val Some(ticks(inside)) = ticks findFirstIn mydata // may throw exception

val ticks = ".*'([^']*)'.*".r    
val ticks(inside) = mydata // safe, shorter, only gets the first set of ticks


1

Apache Commons Lang fournit une multitude d'utilitaires d'assistance pour l'API java.lang, notamment les méthodes de manipulation de chaînes. Dans votre cas, les sous-chaînes de début et de fin sont les mêmes, il suffit donc d'appeler la fonction suivante.

StringUtils.substringBetween(String str, String tag)

Obtient la chaîne imbriquée entre deux instances de la même chaîne .

Si les sous-chaînes de début et de fin sont différentes, utilisez la méthode surchargée suivante.

StringUtils.substringBetween(String str, String open, String close)

Obtient la chaîne imbriquée entre deux chaînes.

Si vous voulez toutes les instances des sous-chaînes correspondantes, utilisez alors,

StringUtils.substringsBetween(String str, String open, String close)

Recherche dans une chaîne des sous-chaînes délimitées par une balise de début et de fin, renvoyant toutes les sous-chaînes correspondantes dans un tableau .

Pour l'exemple en question pour obtenir toutes les instances de la sous-chaîne correspondante

String[] results = StringUtils.substringsBetween(mydata, "'", "'");

0

vous pouvez utiliser cette i boucle while pour stocker toutes les sous-chaînes de correspondance dans le tableau si vous utilisez

if (matcher.find()) { System.out.println(matcher.group(1)); }

vous obtiendrez des sous-chaînes de correspondance afin que vous puissiez l'utiliser pour obtenir toutes les sous-chaînes de correspondances

Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+").matcher(text);
   // Matcher  mat = pattern.matcher(text);
    ArrayList<String>matchesEmail = new ArrayList<>();
        while (m.find()){
            String s = m.group();
            if(!matchesEmail.contains(s))
                matchesEmail.add(s);
        }

    Log.d(TAG, "emails: "+matchesEmail);

0

ajouter la dépendance apache.commons à votre pom.xml

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>

Et le code ci-dessous fonctionne.

StringUtils.substringBetween(String mydata, String "'", String "'")

0

Certains comment le groupe (1) n'a pas fonctionné pour moi. J'ai utilisé le groupe (0) pour trouver la version URL.

Pattern urlVersionPattern = Pattern.compile("\\/v[0-9][a-z]{0,1}\\/");
Matcher m = urlVersionPattern.matcher(url);
if (m.find()) { 
    return StringUtils.substringBetween(m.group(0), "/", "/");
}
return "v0";
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.