Les chaînes de caractères

Les chaînes de caractères, représentées par l'objetString, ont déjà été manipulées au sein de ce cours, mais il reste bien des choses à voir à leur propos ! Nous allons dans un premier temps découvrir les types primitifs car cela nous sera nécessaire pour vraiment parler des objets commeString,RegExpet autres que nous verrons par la suite.

Les types primitifs

Nous avons vu, tout au long du cours, que les chaînes de caractères étaient des objetsString, les tableaux desArray, etc. C'est toujours vrai mais il convient de nuancer ces propos en introduisant le concept de type primitif.

Pour créer une chaîne de caractères, on utilise généralement cette syntaxe :

var myString = "Chaîne de caractères primitive";

Cet exemple crée ce que l'on appelle une chaîne de caractères primitive, qui n'est pas un objetString. Pour instancier un objetString, il faut faire comme ceci :

var myRealString = new String("Chaîne");

Cela est valable pour les autres objets :

var myArray = []; // Tableau primitif
var myRealArray = new Array();
var myObject = {}; // Objet primitif
var myRealObject = new Object();
var myBoolean = true; // Booléen primitif
var myRealBoolean = new Boolean("true");
var myNumber = 42; // Nombre primitif
var myRealNumber = new Number("42");

Ce que nous avons utilisé jusqu'à présent était en fait des types primitifs, et non des instances d'objets.

Quelle est la différence entre un type primitif et une instance ?

La différence est minime pour nous, développeurs. Prenons l'exemple de la chaîne de caractères : à chaque fois que nous allons faire une opération sur une chaîne primitive, le JavaScript va automatiquement convertir cette chaîne en une instance temporaire deString, de manière à pouvoir utiliser les propriétés et méthodes fournies par l'objetString. Une fois les opérations terminées, l'instance temporaire est détruite.

Au final, utiliser un type primitif ou une instance revient au même du point de vue de l'utilisation. Mais il subsiste de légères différences avec l'opérateurinstanceofqui peut retourner de drôles de résultats…

Pour une raison ou une autre, imaginons que l'on veuille savoir de quelle instance est issu un objet :

var myString = 'Chaîne de caractères';
if (myString instanceof String) {
// Faire quelque chose
}

La condition sera fausse ! Et c'est bien normal puisquemyStringest une chaîne primitive et non une instance deString. Pour tester le type primitif, il convient d'utiliser l'opérateurtypeof:

if (typeof myString === 'string') {
// Faire quelque chose
}

typeofpermet de vérifier le type primitif (en anglais on parle de datatype). Mais ici aussi faites attention au piège, car la forme primitive d'une instance deStringest…object:

alert(typeof myRealString); // Affiche : « object »

Il faudra donc faire bien attention en testant le type ou l'instance d'un objet ! Il est même d'ailleurs déconseillé de faire ce genre de tests vu le nombre de problèmes que cela peut causer. La seule valeur retournée partypeofdont on peut être sûr, c'est"undefined". Nous allons étudier, plus tard dans ce chapitre, une solution pour tester si une variable contient une chaîne de caractères.

L'objet String

L'objetStringest l'objet que vous manipulez depuis le début du tutoriel : c'est lui qui gère les chaînes de caractères.

Propriétés

Stringne possède qu'une seule propriété,length, qui retourne le nombre de caractères contenus dans une chaîne. Les espaces, les signes de ponctuation, les chiffres… sont considérés comme des caractères. Ainsi, cette chaîne de caractères contient 21 caractères :

alert('Ceci est une chaîne !'.length);

Essayer le code

Mais ! C'est quoi cette manière d'écrire du code ?

En fait, il n'est pas toujours obligatoire de déclarer une variable pour utiliser les propriétés et les méthodes d'un objet. En effet, vous pouvez écrire directement le contenu de votre variable et utiliser une de ses propriétés ou de ses méthodes, comme c'est le cas ici. Notez cependant que cela ne fonctionne pas avec les nombres sous forme primitive car le point est le caractère permettant d'ajouter une ou plusieurs décimales. Ainsi, ce code générera une erreur :

0.toString(); // Une erreur se produira si vous exécutez ce code

Méthodes

Stringpossède quelques méthodes qui sont pour la plupart assez intéressantes mais basiques. Le JavaScript est un langage assez simple, qui ne contient pas énormément de méthodes de base. C'est un peu l'inverse du PHP qui contient une multitude de fonctions pour réaliser un peu tout et n'importe quoi. Par exemple, le PHP possède une fonction pour mettre la première lettre d'une chaîne en majuscule, alors qu'en JavaScript il faudra nous-mêmes récupérer le premier caractère et le mettre en majuscule. Le JavaScript fournit juste quelques méthodes de base, et ce sera à vous de coder vous-mêmes d'autres méthodes ou fonctions selon vos besoins.

La casse et les caractères

toLowerCase()ettoUpperCase()

toLowerCase()ettoUpperCase()permettent respectivement de convertir une chaîne en minuscules et en majuscules. Elles sont pratiques pour réaliser différents tests ou pour uniformiser une chaîne de caractères. Leur utilisation est simple :

var myString = 'tim berners-lee';
myString = myString.toUpperCase(); // Retourne : « TIM BERNERS-LEE »

Accéder aux caractères

La méthodecharAt()permet de récupérer un caractère en fonction de sa position dans la chaîne de caractères. La méthode reçoit en paramètre la position du caractère :

var myString = 'Pauline';
var first = myString.charAt(0); // P
var last = myString.charAt(myString.length - 1); // e

En fait, les chaînes de caractères peuvent être imaginées comme des tableaux, à la différence qu'il n'est pas possible d'accéder aux caractères en utilisant les crochets : à la place, il faut utilisercharAt().

Obtenir le caractère en ASCII

La méthodecharCodeAt()fonctionne commecharAt()à la différence que ce n'est pas le caractère qui est retourné mais le code ASCII du caractère.

Créer une chaîne de caractères depuis une chaîne ASCII

fromCharCode()permet de faire plus ou moins l'inverse decharCodeAt(): instancier une nouvelle chaîne de caractères à partir d'une chaîne ASCII, dont chaque code est séparé par une virgule. Son fonctionnement est particulier puisqu'il est nécessaire d'utiliser l'objetStringlui-même :

var myString = String.fromCharCode(74, 97, 118, 97, 83, 99, 114, 105, 112, 116); // le mot JavaScript en ASCII
alert(myString); // Affiche : « JavaScript »

Mais quel est l'intérêt d'utiliser les codes ASCII ?

Ce n'est pas très fréquent, mais cela peut être utile dans un cas bien particulier : détecter les touches du clavier. Admettons qu'il faille savoir quelle touche du clavier à été pressée par l'utilisateur. Pour cela, on utilise la propriétékeyCodede l'objetEvent:

<textarea onkeyup="listenKey(event)"></textarea>

La fonctionlistenKey()peut être écrite comme suit :

function listenKey(event) {
var key = event.keyCode;
alert('La touche numéro ' + key + ' a été pressée. Le caractère ' + String.fromCharCode(key) + ' a été inséré.');
}

Essayer le code complet

event.keyCoderetourne le code ASCII qui correspond au caractère inséré par la touche. Pour la touche J, le code ASCII est 74 par exemple.

Supprimer les espaces avectrim()

trim() sert à supprimer les espaces avant et après une chaîne de caractères. C'est particulièrement utile quand on récupère des données saisies dans une zone de texte, car l'utilisateur est susceptible d'avoir laissé des espaces avant et après son texte, surtout s'il a fait un copier/coller.

Rechercher, couper et extraire

Connaître la position avecindexOf()etlastIndexOf()

La méthodeindexOf()est utile dans deux cas de figure :

  • Savoir si une chaîne de caractères contient un caractère ou un morceau de chaîne ;

  • Savoir à quelle position se trouve le premier caractère de la chaîne recherchée.

indexOf()retourne la position du premier caractère trouvé, et s'il n'y en a pas la valeur -1 est retournée.

var myString = 'Le JavaScript est plutôt cool';
var result = myString.indexOf('JavaScript');
if (result > -1) {
alert('La chaîne contient le mot "JavaScript" qui débute à la position ' + result);
}

Essayer le code

Ce code a pour but de savoir si la chaînemyStringcontient la chaîne « JavaScript ». La position de la première occurrence de la chaîne recherchée est stockée dans la variableresult. Siresultvaut -1, alors la chaîne n'a pas été trouvée. Si, en revanche,resultvaut 0 (le premier caractère) ou une autre valeur, la chaîne est trouvée.

SiindexOf()retourne la position de la première occurrence trouvée,lastIndexOf()retourne la position de la dernière.

Notons que ces deux fonctions possèdent chacune un deuxième argument qui permet de spécifier à partir de quel index la recherche doit commencer.

Utiliser le tilde avecindexOf()etlastIndexOf()

Une particularité intéressante et relativement méconnue du JavaScript est son caractère tilde ~. Il s'agit de l'opérateur binaire « NOT » qui a pour rôle d'inverser tous les bits d'une valeur. Comme le binaire ne nous sert pas à grand chose dans le cadre de notre apprentissage, il est plus logique d'expliquer son influence sur les nombres en base décimale : le tilde incrémente la valeur qui le suit et y ajouter une négation, comme ceci :

alert(~2); // Affiche : « -3 »
alert(~3); // Affiche : « -4 »
alert(~-2); // Affiche : « 1 »

Hum... Ça ne servirait pas un peu à rien, ce truc ?

Eh bien pas tant que ça ! Le tilde est effectivement très peu utile en temps normal, mais dans le cadre d'une utilisation avec les deux méthodes étudiées, il est redoutablement efficace pour détecter si une chaîne de caractères contient un caractère ou un morceau de chaîne. En temps normal nous ferions comme ceci :

var myString = 'Le JavaScript est plutôt cool';
if (myString.indexOf('JavaScript') != -1) {
alert('La chaîne contient bien le mot "JavaScript".');
}

Mais au final il est possible d'ajouter un simple petit tilde ~ à la ligne 3 :

var myString = 'Le JavaScript est plutôt cool';
if (~myString.indexOf('JavaScript')) {
alert('La chaîne contient bien le mot "JavaScript".');
}

En faisant cela, dans le cas où le résultat serait -1, celui-ci va alors se retrouver incrémenté et arriver à 0, ce qui donnera donc une évaluation àfalsepour notre chaîne de caractères. La valeur -1 étant la seule à pouvoir atteindre la valeur 0 avec le tilde ~, il n'y a pas d'hésitation à avoir vu que tous les autres nombres seront évalués àtrue!

Oui, cette technique a été conçue pour les parfaits fainéants, mais il y a fort à parier que vous vous en souviendrez. ^^

Extraire une chaîne avecsubstring(),substr()etslice()

Nous avons vu comment trouver la position d'une chaîne de caractères dans une autre, il est temps de voir comment extraire une portion de chaîne, à partir de cette position.

Considérons cette chaîne :

var myString = 'Thunderseb et Nesk';

Le but du jeu va être de récupérer, dans deux variables différentes, les deux pseudonymes contenus dansmyString. Pour ce faire, nous allons utilisersubstring().substring(a, b)permet d'extraire une chaîne à partir de la positiona(incluse) jusqu'à la positionb(exclue).

Pour extraire « Thunderseb », il suffit de connaître la position du premier espace, puisque la position de départ vaut 0 :

var nick_1 = myString.substring(0, myString.indexOf(' '));

Pour « Nesquik69 », il suffit de connaître la position du dernier espace : c'est à ce moment que commencera la chaîne. Comme «Nesquik69 » termine la chaîne, il n'y a pas besoin de spécifier de deuxième paramètre poursubstring(), la méthode va automatiquement aller jusqu'au bout :

var nick_2 = myString.substring(myString.lastIndexOf(' ') + 1); // Ne pas oublier d'ajouter 1, pour commencer au N et non à l'espace

Une autre manière de procéder serait d'utilisersubstr(), la méthode sœur desubstring().substr(a, n)accepte deux paramètres : le premier est la position de début, et le deuxième le nombre de caractères à extraire. Cela suppose donc de connaître le nombre de caractères à extraire. Ça limite son utilisation et c'est une méthode que vous ne rencontrerez pas fréquemment, au contraire desubstring().

Une dernière méthode d'extraction existe :slice().slice()ressemble très fortement àsubstring(), mais avec une option en plus. Une valeur négative est transmise pour la position de fin,slice()va extraire la chaîne jusqu'à la fin, en décomptant le nombre de caractères indiqué. Par exemple, si on ne veut récupérer que « Thunder », on peut faire comme ceci :

var nick_1 = 'Thunderseb'.slice(0, -3);

Couper une chaîne en un tableau avecsplit()

La méthodesplit()permet de couper une chaîne de caractères à chaque fois qu'une sous-chaîne est rencontrée. Les « morceaux » résultant de la coupe de la chaîne sont placés dans un tableau.

var myCSV = 'Pauline,Guillaume,Clarisse'; // CSV = Comma-Separated Values
var splitted = myCSV.split(','); // On coupe à chaque fois qu'une virgule est rencontrée
alert(splitted.length); // 3

Essayer le code

Dans cet exemple,splittedcontient un tableau contenant trois éléments : « Pauline », « Guillaume » et « Clarisse ».

Tester l'existence d'une chaîne de caractères

Nous l'avons vu plus haut, l'instructiontypeofest utile, mais la seule valeur de confiance qu'elle retourne est"undefined". En effet, lorsqu'une variable contient le type primitif d'une chaîne de caractères,typeofretourne bien la valeur"string", mais si la variable contient une instance deStringalors on obtient en retour la valeur"object". Ce qui fait quetypeofne fonctionne que dans un cas sur deux, il nous faut donc une autre solution pour gérer le deuxième cas.

Et cette solution existe ! Il s'agit de la méthodevalueOf()qui est héritée deObject. Cette méthode renvoie la valeur primitive de n'importe quel objet. Ainsi, si on crée une instance deString:

var string_1 = new String('Test');

et que l'on récupère le résultat de sa méthodevalueOf()dans la variablestring_2:

var string_2 = string_1.valueOf();

alors l'instructiontypeofmontre bien questring_1est une instance deStringet questring_2est une valeur primitive :

alert(typeof string_1); // Affiche : « object »
alert(typeof string_2); // Affiche : « string »

Essayer le code complet

Grâce à cette méthode, il devient bien plus simple de vérifier si une variable contient une chaîne de caractères. Voici notre code final :

function isString(variable) {
return typeof variable.valueOf() === 'string'; // Si le type de la valeur primitive est « string » alors on retourne « true »
}

D'accord, cette fonction va s'exécuter correctement si on envoie une instance deString. Mais que va renvoyervalueOf()si on passe une valeur primitive à notre fonction ?

Eh bien, tout simplement la même valeur. Expliquons-nous :valueOf()retourne la valeur primitive d'un objet, mais si cette méthode est utilisée sur une valeur qui est déjà de type primitif, alors elle va retourner la même valeur primitive, ce qui convient très bien vu que dans tous les cas il s'agit de la valeur primitive que nous souhaitons analyser !

Pour vous convaincre, testez donc par vous-mêmes :

alert(isString('Test')); // Affiche : « true »
alert(isString(new String('Test'))); // Affiche : « true »

Essayer le code complet

Notre fonction marche dans les deux cas. :) Alors, est-ce qu'en pratique vous aurez besoin d'une fonction pareille ? La réponse est : assez peu… Mais il est toujours bon de savoir comment s'en servir, non ?

Et enfin, à titre d'information, sachez qu'il est aussi possible d'obtenir une instanciation d'objet à partir d'un type primitif (autrement dit, on fait l'inverse devalueOf()), il suffit de procéder de cette manière :

var myString = Object('Mon texte');

Pour rappel,Objectest l'objet dont tous les autres objets (tel queString) héritent. Ainsi, en créant une instance deObjectavec un type primitif en paramètre, l'objet instancié sera de même type que la valeur primitive. En clair, si vous passez en paramètre un type primitifstringalors vous obtiendrez une instance de l'objetStringavec la même valeur passée en paramètre.

En résumé
  • Il existe des objets et des types primitifs. Si leur utilisation semble identique, il faut faire attention lors des tests avec les opérateursinstanceofettypeof. Mais heureusementvalueOf()sera d'une aide précieuse.

  • Il est préférable d'utiliser les types primitifs, comme nous le faisons depuis le début de ce cours.

  • Stringfournit des méthodes pour manipuler les caractères : mettre en majuscule ou en minuscule, récupérer un caractère grâce à sa position et supprimer les espaces de part et d'autre de la chaîne.

  • Stringfournit aussi des méthodes pour rechercher, couper et extraire.

  • L'utilisation du caractère tilde est méconnue, mais peut se révéler très utile en couple avecindexOf()oulastIndexOf().