2023-07-25 10:48 Temps de lecture : 20 min

Comprendre la sous-chaîne en Java : un guide de base

Dans cet exposé, nous allons explorer en profondeur la notion de sous-chaînes en Java. Nous allons combiner des explications théoriques claires avec des exemples de code concrets pour faciliter votre compréhension. L'objectif est de vous rendre autonome dans la création et la manipulation de sous-chaînes, ainsi que dans la recherche de ces dernières au sein de chaînes de caractères plus vastes.

Toutefois, avant de nous plonger dans les techniques avancées, il est crucial de maîtriser les bases concernant les chaînes et les sous-chaînes.

Définition des chaînes et sous-chaînes

En Java, une chaîne est définie comme une séquence ordonnée de caractères. Chaque chaîne est traitée comme un objet en Java, capable de contenir des lettres, des chiffres, des symboles, et même des espaces. Une sous-chaîne, quant à elle, représente une portion, une partie d'une chaîne Java existante. C'est un sous-ensemble de la chaîne d'origine.

Par exemple, "Tech" est une sous-chaîne de "Technologie". L'intérêt principal des sous-chaînes réside dans leur capacité à isoler des segments spécifiques d'une chaîne.

Si l'on prend le nom "Alice Dupont", et que l'on souhaite extraire uniquement le prénom "Alice", les sous-chaînes deviennent indispensables. De même, si l'on dispose d'une liste de noms comme "Pierre, Paul, Jacques" et que l'on veut vérifier si "Paul" y figure, les sous-chaînes sont l'outil adéquat. Ces situations illustrent la polyvalence des sous-chaînes, et une fois leur fonctionnement maîtrisé, leur utilisation devient naturelle dans de nombreuses opérations.

Maintenant que nous avons établi le concept de sous-chaîne en Java, il est temps d'apprendre à les créer et à les utiliser.

#1. Utilisation de la méthode `substring()`

La méthode `substring()` est un outil puissant pour créer des sous-chaînes de manière intuitive. Elle accepte un ou deux paramètres : soit un indice de début (`startIndex`), soit un indice de début et un indice de fin (`startIndex` et `endIndex`). En retour, elle fournit la sous-chaîne désirée.

L'usage de cette méthode varie selon le nombre de paramètres. Examinons les deux cas plus en détail.

`substring(int startIndex)`

La première forme de la méthode est `substring(startIndex)`. Elle prend un entier en entrée, qui correspond à la position de départ de la sous-chaîne. La méthode retourne une chaîne qui commence à l'indice fourni et se poursuit jusqu'à la fin de la chaîne initiale.

Considérons cet exemple de code pour illustrer le propos :

public class SousChaines {
    public static void main(String[] args) {
        String str = "exemple.com";
        System.out.println("Chaîne d'origine: " + str);
        System.out.println("Sous-chaîne: " + str.substring(4));
    }
}

Résultat :

Chaîne d'origine: exemple.com
Sous-chaîne: ple.com

Comme on peut le voir, la chaîne de départ est "exemple.com", et le résultat est la sous-chaîne "ple.com". Cette sous-chaîne est créée à partir de l'indice 4 (la 5ème position), et s'étend jusqu'à la fin de la chaîne d'origine.

`substring(int startIndex, int endIndex)`

Une autre manière d'employer la méthode `substring` de la classe `String` consiste à lui fournir deux entiers : un indice de départ et un indice de fin. Sa syntaxe est `substring(startIndex, endIndex)`.

Afin de clarifier son fonctionnement, prenons l'exemple de code suivant :

public class SousChaines {
    public static void main(String[] args) {
        String str = "CodeFacileJava";
        System.out.println("Chaîne d'origine: " + str);
        System.out.println("Sous-chaîne: " + str.substring(4, 10));
    }
}

Résultat :

Chaîne d'origine: CodeFacileJava
Sous-chaîne: Facile

Dans ce cas, à partir de la chaîne "CodeFacileJava", nous obtenons la sous-chaîne "Facile". L'indice de départ est 4 et celui de fin est 10. La sous-chaîne inclut les caractères à partir de l'indice 4, et s'arrête avant l'indice 10. Il est important de noter que l'élément à l'indice de fin est exclu du résultat. La sous-chaîne obtenue comprend tous les éléments jusqu'à l'indice de fin, mais sans inclure celui correspondant à l'indice de fin lui-même.

#2. Utilisation de la méthode `split()`

La méthode `split()` est une autre méthode de la classe `String` en Java qui peut être utilisée pour créer des sous-chaînes. Elle est particulièrement utile lorsque des informations sont stockées dans une seule chaîne, séparées par un délimiteur commun.

La syntaxe mentionne le terme "regex", qui peut sembler intimidant. Clarifions ce que signifie "regex" avant de continuer. Regex est l'abréviation de "Expressions Régulières". Une expression régulière est une séquence de caractères qui décrit un motif dans une chaîne de caractères ou un texte. Dans le contexte de la méthode split, la regex est notre délimiteur.

La méthode `split()` accepte jusqu'à deux paramètres : une chaîne regex et un entier limit. La regex est le séparateur qui, lorsqu'il est détecté, divise la chaîne d'origine en deux parties : la partie avant la regex, et la partie après.

Par exemple, si nous voulons diviser la chaîne "abcdef" avec "bcd" comme regex, nous obtiendrions les sous-chaînes "a" et "ef" comme résultat.

La méthode renvoie un tableau contenant les chaînes séparées. On peut spécifier uniquement la regex, ou la regex ainsi qu'une limite. Étudions les différentes manières d'appeler cette méthode.

`split(String regex)`

La première forme de la méthode ne reçoit que la chaîne regex au format `split(regex)`. N'ayant pas de limite spécifiée, elle renvoie toutes les sous-chaînes séparées dans un tableau.

Illustrons cela avec un exemple :

public class SousChaines {
    public static void main(String[] args) {
        String str = "Java-Script";
        String[] sousChaines = str.split("-");
        System.out.println("Chaîne d'origine: " + str);
        System.out.println("Première sous-chaîne: " + sousChaines[0]);
        System.out.println("Seconde sous-chaîne: " + sousChaines[1]);
    }
}

Résultat :

Chaîne d'origine: Java-Script
Première sous-chaîne: Java
Seconde sous-chaîne: Script

Comme le montre le code, la chaîne de départ a un séparateur regex "-". Ce séparateur n'est pas nécessairement un unique caractère ; il peut s'agir de n'importe quelle chaîne, quelle que soit sa longueur. La méthode `split()` ignore cette regex et fournit toutes les chaînes séparées par cette regex. Les sous-chaînes sont ensuite stockées dans un tableau.

Dans l'exemple, la chaîne donnée est "Java-Script". On obtient donc un tableau de deux éléments : "Java" et "Script". On accède ensuite à ces éléments en utilisant leur index (respectivement 0 et 1), et on affiche "Java" et "Script" à la console.

Il est important de noter ici que si aucun paramètre n'est fourni à la méthode, une erreur sera générée. Par contre, si l'on fournit une chaîne vide ("") comme regex, on obtient chaque caractère individuel comme sous-chaîne. L'exemple suivant va illustrer ce point.

import java.util.Arrays;

public class SousChaines {
    public static void main(String[] args) {
        String str = "Java-Script";
        String[] sousChaines = str.split("");
        System.out.println(Arrays.toString(sousChaines));
    }
}

Résultat :

[J, a, v, a, -, S, c, r, i, p, t]

L'exemple met en évidence qu'avec un paramètre regex vide, la méthode retourne chaque caractère en tant que sous-chaîne distincte, ce qui est visible lors de l'affichage du tableau renvoyé par `split()`.

`split(String regex, int limit)`

Cette deuxième version de la méthode nous offre plus de contrôle sur le résultat, et permet d'affiner davantage l'action de la méthode `split()`. Ici, la méthode `split()` prend deux variables en entrée. En plus de la regex, on spécifie également un paramètre de limite sous la forme `split(regex, limit)`.

La `limit` correspond au nombre de chaînes résultantes à produire. Selon la valeur de la limite, on peut identifier trois cas distincts :

Cas 1 : Si limit>0, le tableau résultant contiendra le résultat du fractionnement, mais appliquera au maximum `(limit - 1)` séparations. Le tableau obtenu ne contiendra pas plus d'éléments que la limite spécifiée, et toute la chaîne non fractionnée restante sera conservée telle quelle. Illustrons ce cas avec un exemple de code.

import java.util.Arrays;

public class SousChaines {
    public static void main(String[] args) {
        String str = "a%b%c%d%e";
        String[] sousChaines = str.split("%", 2);
        System.out.println(Arrays.toString(sousChaines));
    }
}

Résultat :

[a, b%c%d%e]

On observe que dans le résultat, il n'y a que deux éléments dans le tableau, ce qui correspond à la valeur fournie dans le paramètre limit. Il est également à noter que le fractionnement n'est appliqué qu'une seule fois (limit - 1).

Cependant, si la regex apparaît deux fois de suite ("%%"), des sous-chaînes vides sont produites. L'exemple de code suivant va permettre de mieux le comprendre.

import java.util.Arrays;

public class SousChaines {
    public static void main(String[] args) {
        String str = "a%b%c%%d%e%%%";
        String[] sousChaines = str.split("%", 5);
        System.out.println(Arrays.toString(sousChaines));
    }
}

Résultat :

[a, b, c, , d%e%%%]

En substance, chaque occurrence de "%" suivie d'un autre "%" ou de la fin de la chaîne se traduit par une sous-chaîne vide.

Cas 2 : Si limit<0, l'opération de fractionnement sera appliquée autant de fois que possible sans aucune limite sur la taille du tableau, mais le tableau contiendra des sous-chaînes vides si la regex est présente deux fois de suite ("%%").

import java.util.Arrays;

public class SousChaines {
    public static void main(String[] args) {
        String str = "a%b%c%%d%e%%%";
        String[] sousChaines = str.split("%", -1);
        System.out.println(Arrays.toString(sousChaines));
    }
}

Résultat :

[a, b, c, , d, e, , , ]

Il apparaît clairement, d'après le résultat, que le fractionnement est appliqué autant de fois que possible et que des sous-chaînes vides sont également présentes.

Cas 3 : Si limit=0, l'opération de fractionnement sera également appliquée autant de fois que possible, mais toutes les sous-chaînes vides à la fin de la chaîne seront supprimées du tableau.

import java.util.Arrays;

public class SousChaines {
    public static void main(String[] args) {
        String str = "a%b%c%%d%e%%%";
        String[] sousChaines = str.split("%", 0);
        System.out.println(Arrays.toString(sousChaines));
    }
}

Résultat :

[a, b, c, , d, e]

On remarque une similarité entre les résultats obtenus avec limit=-1 et limit=0, à l'exception de l'absence de sous-chaînes vides à la fin. En d'autres termes, les sous-chaînes vides situées à la fin du tableau de sous-chaînes sont ignorées.

Notons également que si la regex n'est pas présente dans la chaîne, la méthode retournera la chaîne d'origine dans son intégralité.

Vérifier si une chaîne contient une sous-chaîne

Outre la création de sous-chaînes à partir de chaînes existantes, il est également possible de vérifier si une sous-chaîne donnée est présente dans une chaîne plus large. Cette fonctionnalité permet de simplifier et d'accélérer la vérification de la présence de sous-chaînes, ce qui s'avère utile dans de nombreuses situations. Mais comment cela fonctionne-t-il ? Diverses méthodes sont disponibles pour y parvenir. Examinons-les une par une.

Utilisation de la méthode `contains()`

On peut vérifier très facilement la présence d'une sous-chaîne grâce à la méthode `contains()`. Cette méthode de la classe `String` prend en entrée une chaîne de caractères, qui correspond à notre sous-chaîne, et retourne une valeur booléenne indiquant si la sous-chaîne est présente ou non à l'intérieur de la chaîne. Cette méthode peut être utilisée dans des blocs `if-else`, des opérateurs ternaires, et dans d'autres contextes pour implémenter des logiques complexes.

Étudions cette méthode de plus près.

public class SousChaines {
    public static void main(String[] args) {
        String str = "example.fr";
        System.out.println("Contient 'ample' ? " + str.contains("ample"));
    }
}

Résultat :

Contient 'ample' ? true

Dans cet exemple, le code vérifie si la chaîne "example.fr" contient le mot "ample". Étant donné qu'il le trouve, la méthode retourne un booléen "true", confirmant ainsi la présence de la sous-chaîne.

public class SousChaines {
    public static void main(String[] args) {
        String str = "example.fr";
        System.out.println("Contient 'ample1' ? " + str.contains("ample1"));
    }
}

Résultat :

Contient 'ample1' ? false

Cet exemple montre que si la sous-chaîne n'est pas contenue dans la chaîne, la méthode retournera `false`, signifiant son absence. On peut donc se fier facilement au résultat pour savoir si une sous-chaîne existe.

Recherche de la position d'une sous-chaîne

#1. Utilisation de `indexOf()`

La méthode `indexOf()` peut être utilisée pour confirmer l'existence d'une sous-chaîne et obtenir son indice. Cette méthode prend en entrée une chaîne ou un caractère et nous donne la position de sa première occurrence. Cependant, elle ne peut que nous indiquer l'indice de la première occurrence et ne confirme pas s'il existe d'autres occurrences. Autre point à retenir : si la sous-chaîne n'existe pas, la méthode retourne -1.

Examinons cette méthode plus en détail.

public class SousChaines {
    public static void main(String[] args) {
        String str = "CodeJavaCode";
        System.out.println("Indice de 'Code': " + str.indexOf("Code"));
    }
}

Résultat :

Indice de 'Code': 0

Dans cet exemple, la première occurrence de la sous-chaîne "Code" commence à l'indice 0 dans la chaîne "CodeJavaCode". La méthode a retourné l'indice correctement.

#2. Utilisation de `lastIndexOf()`

La méthode `lastIndexOf()` est très similaire à `indexOf()`. Ces deux méthodes prennent la sous-chaîne comme entrée et renvoient l'indice de sa position. Elles retournent également la même valeur en cas d'échec : -1.

La différence réside dans le fait que `indexOf()` retourne l'indice de la première occurrence de la sous-chaîne, tandis que `lastIndexOf()` retourne celui de la dernière.

Voyons son fonctionnement à travers un exemple de code :

public class SousChaines {
    public static void main(String[] args) {
        String str = "CodeJavaCode";
        System.out.println("Dernier indice de 'Code': " + str.lastIndexOf("Code"));
    }
}

Résultat :

Dernier indice de 'Code': 8

Comme le montre ce résultat, la méthode `lastIndexOf()` fonctionne comme prévu, en retournant l'indice de la dernière occurrence de la sous-chaîne "Code" dans la chaîne "CodeJavaCode".

FAQ

Comment utiliser la méthode `split()` pour créer des sous-chaînes non vides ?

S'il y a plusieurs instances de la regex dans la chaîne principale se suivant directement (comme dans "Bonjour%%Salut", avec "%" comme regex), la méthode `split()` considère la première instance comme le point de rupture, et les autres génèrent une chaîne vide. Afin de pallier cela, on peut spécifier le paramètre `limit` à 0. Ainsi, seules les chaînes non vides seront renvoyées.

`indexOf()` retourne-t-il les indices de toutes les instances d'une sous-chaîne ?

Non, `indexOf()` ne retourne pas les indices de toutes les instances d'une sous-chaîne. Avec `indexOf()`, on obtient une valeur entière correspondant à l'indice de la première occurrence de la sous-chaîne. Si la sous-chaîne n'est pas trouvée, la méthode retournera -1.

Que retourne la méthode `substring()` si les indices fournis n'existent pas dans la chaîne ?

Si l'indice de début ou l'indice de fin n'existent pas dans la chaîne, le compilateur renverra une erreur. L'erreur affichera "java.lang.StringIndexOutOfBoundsException:" et le programme s'arrêtera.

Conclusion

Dans cet article, nous avons abordé différentes méthodes et concepts clés pour commencer à travailler avec les sous-chaînes. Nous avons traité de la création de sous-chaînes, ainsi que de la vérification de leur existence au sein d'une chaîne. Grâce à ces informations, vous devriez avoir une meilleure compréhension de la manipulation des sous-chaînes. N'hésitez pas à consulter les exemples et à pratiquer davantage pour maîtriser pleinement les sous-chaînes.

Pour aller plus loin, vous pouvez consulter notre liste de questions d'entretien Java.

Auteur
France

Rédacteur tech, guides pratiques et astuces numériques.