JavaScript utilise l’encodage Unicode pour les chaînes de cractères. La plupart des caractères sont codés sur 2 octets, mais cela permet de représenter au plus 65536 caractères.
Cette plage n’est pas assez grande pour encoder tous les caractères possibles, c’est pourquoi certains caractères rares sont encodés sur 4 octets, par exemple comme 𝒳
(X mathématique) ou 😄
(un sourire), certains hiéroglyphes et ainsi de suite.
Voici les valeurs unicode de certains caractères :
Caractère | Unicode | Nombre d’octets en unicode |
---|---|---|
a | 0x0061 |
2 |
≈ | 0x2248 |
2 |
𝒳 | 0x1d4b3 |
4 |
𝒴 | 0x1d4b4 |
4 |
😄 | 0x1f604 |
4 |
Ainsi, les caractères comme a
et ≈
occupent 2 octets, tandis que les codes pour 𝒳
, 𝒴
et 😄
sont plus longs, ils ont 4 octets.
Il y a longtemps, lorsque le langage JavaScript a été créé, l’encodage Unicode était plus simple : il n’y avait pas de caractères à 4 octets. Ainsi, certaines fonctionnalités du langage les gèrent toujours de manière incorrecte.
Par exemple, la propriété length
pense qu’il y a deux caractères :
alert('😄'.length); // 2
alert('𝒳'.length); // 2
… Mais nous pouvons voir qu’il n’y en a qu’un, n’est-ce pas? Le fait est que la propriété length
traite 4 octets comme deux caractères de 2 octets. C’est incorrect, car ils doivent être considérés uniquement ensemble (aussi appelé “paire de substitution”, vous pouvez en lire plus dans l’article Strings).
Par défaut, les expressions régulières traitent également les “caractères longs” de 4 octets comme une paire de caractères de 2 octets. Et, comme cela arrive avec les chaînes, cela peut conduire à des résultats étranges. Nous verrons cela un peu plus tard, dans l’article Ensembles et intervalles [...].
Contrairement aux chaînes de caractères, les expressions régulières ont l’indicateur u
qui résout ces problèmes. Avec un tel indicateur, une expression rationnelle gère correctement les caractères de 4 octets. Et ainsi la recherche de propriétés Unicode devient également disponible, nous y reviendrons ensuite.
Propriétés Unicode \p{…}
Chaque caractère dans Unicode a beaucoup de propriétés. Ils décrivent à quelle “catégorie” le caractère appartient, et contiennent diverses informations à son sujet.
Par exemple, si un caractère a la propriété Letter
(Lettre), cela signifie que le caractère appartient à un alphabet (de n’importe quelle langue). Et la propriété Number
(Nombre) signifie que c’est un chiffre : peut-être l’arabe ou le chinois, et ainsi de suite.
Nous pouvons rechercher des caractères avec une propriété, écrite sous la forme \p{…}
. Pour utiliser \p{…}
, une expression régulière doit avoir l’indicateur u
.
Par exemple, \p{Letter}
désigne une lettre dans n’importe quelle langue. Nous pouvons également utiliser \p{L}
, car L
est un alias de Letter
(Lettre). Il existe des alias plus courts pour presque toutes les propriétés.
Dans l’exemple ci-dessous, on trouvera trois types de lettres : Anglais, Géorgien et Coréen.
let str = "A ბ ㄱ";
alert( str.match(/\p{L}/gu) ); // A,ბ,ㄱ
alert( str.match(/\p{L}/g) ); // null (aucune correspondance, \p ne fonctionne pas sans le flag "u")
Voici les principales catégories de caractères et leurs sous-catégories :
- Lettre
L
:- minuscules
Ll
, - modificateur
Lm
, - titre
Lt
, - majuscule
Lu
, - autres
Lo
.
- minuscules
- Nombre
N
:- chiffre décimal
Nd
, - numéro de lettre
Nl
, - autre
No
.
- chiffre décimal
- Ponctuation
P
:- connecteur
Pc
, - tiret
Pd
, - citation initiale
Pi
, - citation finale
Pf
, - ponctuation ouvrante
Ps
, - ponctuation fermante
Pe
, - autre
Po
.
- connecteur
- Marqueur
M
(accents, etc.) :- espacement combinant
Mc
, - contenant
Me
, - sans espacement
Mn
.
- espacement combinant
- Symbole
S
:- devise
Sc
, - modificateur
Sk
, - mathématique
Sm
, - autre
So
.
- devise
- Séparateur
Z
:- ligne
Zl
, - paragraphe
Zp
, - espace
Zs
.
- ligne
- Autre
C
:- contrôle
Cc
, - format
Cf
, - non affecté
Cn
, - usage privé
Co
, - substitut
Cs
.
- contrôle
Ainsi, par exemple si nous avons besoin de lettres en minuscules, nous pouvons écrire \p{Ll}
, de signes de ponctuation : \p{P}
et ainsi de suite.
Il existe également d’autres catégories dérivées, comme :
Alphabetic
(Alphabétique,Alpha
), qui comprend les lettresL
, plus les numéros de lettreNl
(par exemple Ⅻ – un caractère pour le chiffre romain 12), plus quelques autres symbolesOther_Alphabetic
(Autre alphabétiques,OAlpha
).Hex_Digit
comprend des chiffres hexadécimaux :0-9
,a-f
.- …Et ainsi de suite.
Unicode prend en charge de nombreuses propriétés différentes, leur liste complète nécessiterait beaucoup d’espace, voici donc les références :
- Liste de toutes les propriétés par caractère : https://unicode.org/cldr/utility/character.jsp.
- Liste de tous les caractères par propriété : https://unicode.org/cldr/utility/list-unicodeset.jsp.
- Alias courts pour les propriétés : https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt.
- Une base complète de caractères Unicode au format texte, avec toutes les propriétés, se trouve ici: https://www.unicode.org/Public/UCD/latest/ucd/.
Exemple : nombres hexadécimaux
Par exemple, recherchons des nombres hexadécimaux, écrits sous la forme xFF
, où F
est un chiffre hexadécimal (0…9 ou A…F).
Un chiffre hexadécimal peut être désigné par \p{Hex_Digit}
:
let regexp = /x\p{Hex_Digit}\p{Hex_Digit}/u;
alert("number: xAF".match(regexp)); // xAF
Exemple : Hiéroglyphes Chinois
Cherchons des hiéroglyphes Chinois.
Il y a une propriété unicode Script
(un système d’écriture), qui peut avoir une valeur : Cyrillic
(Cyrillique), Greek
(Grec), Arabic
(Arabe), Han
(Chinois) et ainsi de suite, voici la liste complète.
Pour rechercher des caractères dans un système d’écriture donné, nous devons utiliser Script=<value>
, par exemple pour les lettres cyrilliques : \p{sc=Cyrillic}
, pour les hiéroglyphes chinois : \p{sc=Han}
, et ainsi de suite :
let regexp = /\p{sc=Han}/gu; // renvoie des hiéroglyphes Chinois
let str = `Hello Привет 你好 123_456`;
alert( str.match(regexp) ); // 你,好
Exemple: devise
Les caractères qui désignent une devise, tels que $
, €
, ¥
, ont la propriété unicode \p{Currency_Symbol}
, l’alias court : \p{Sc}
.
Utilisons-le pour rechercher des prix au format “devise, suivi d’un chiffre” :
let regexp = /\p{Sc}\d/gu;
let str = `Prices: $2, €1, ¥9`;
alert( str.match(regexp) ); // $2,€1,¥9
Plus loin, dans l’article Quantificateurs +, *, ? et {n}, nous verrons comment rechercher des nombres contenant de nombreux chiffres.
Résumé
L’indicateur u
permet la prise en charge d’Unicode dans les expressions régulières.
Cela signifie deux choses :
- Les caractères de 4 octets sont traités correctement : comme un seul caractère, pas comme deux caractères de 2 octets.
- Les propriétés Unicode peuvent être utilisées dans la recherche :
\p{…}
.
Avec les propriétés Unicode, nous pouvons rechercher des mots dans des langues données, des caractères spéciaux (guillemets, devises) et ainsi de suite.