API Intl.Collator
Trier et comparer correctement les chaînes de caractères dans toutes les langues
Introduction
Le tri des chaînes de caractères en JavaScript semble simple jusqu'à ce que vous rencontriez du texte international. La comparaison de chaînes par défaut utilise les valeurs des points de code Unicode, produisant des résultats incorrects pour de nombreuses langues. L'API Intl.Collator fournit une comparaison de chaînes adaptée à la locale qui respecte les règles de tri culturelles et gère correctement les caractères spéciaux.
Pourquoi le tri par défaut échoue
Considérons le tri d'une liste de noms allemands :
const names = ["Zoe", "Ava", "Ärzte", "Änder"];
console.log(names.sort());
// ["Ava", "Zoe", "Änder", "Ärzte"]
Ce résultat est incorrect pour les germanophones. En allemand, les caractères avec trémas comme ä devraient être triés près de leur lettre de base a, et non à la fin. Le problème vient du fait que JavaScript compare les valeurs des points de code Unicode, où Ä (U+00C4) vient après Z (U+005A).
Différentes langues ont différentes règles de tri. Le suédois place ä à la fin de l'alphabet, l'allemand le place près de a, et le français traite les caractères accentués différemment. La comparaison binaire ignore ces conventions culturelles.
Comment fonctionne la collation des chaînes
La collation est le processus de comparaison et d'ordonnancement des chaînes selon des règles spécifiques à la langue. L'algorithme de collation Unicode définit comment comparer les chaînes en analysant séparément les caractères, les diacritiques, la casse et la ponctuation.
Lors de la comparaison de deux chaînes, une fonction de collation renvoie un nombre :
- Valeur négative : la première chaîne précède la seconde
- Zéro : les chaînes sont équivalentes pour le niveau de sensibilité actuel
- Valeur positive : la première chaîne suit la seconde
Ce modèle de comparaison à trois voies fonctionne avec Array.sort et permet un contrôle précis sur les différences qui importent.
Utilisation de localeCompare pour un tri de base adapté à la locale
La méthode localeCompare fournit une comparaison de chaînes adaptée à la locale :
const names = ["Zoe", "Ava", "Ärzte", "Änder"];
console.log(names.sort((a, b) => a.localeCompare(b, "de")));
// ["Ava", "Änder", "Ärzte", "Zoe"]
Cela produit un tri allemand correct. Le premier paramètre spécifie la locale, et localeCompare gère automatiquement les règles culturelles.
Vous pouvez passer des options comme troisième paramètre :
const items = ["File10", "File2", "File1"];
console.log(items.sort((a, b) =>
a.localeCompare(b, "en", { numeric: true })
));
// ["File1", "File2", "File10"]
L'option numeric permet un tri naturel où "2" vient avant "10". Sans elle, "10" serait trié avant "2" car "1" vient avant "2".
Le problème de performance avec localeCompare répété
Chaque appel à localeCompare traite les paramètres de locale depuis le début. Lors du tri de grands tableaux, cela crée une surcharge significative :
// Inefficace : traite la locale pour chaque comparaison
const sorted = items.sort((a, b) => a.localeCompare(b, "de"));
Le tri de 1000 éléments nécessite environ 10000 comparaisons. Chaque comparaison recrée la configuration de locale, multipliant le coût en performance. Cette surcharge devient perceptible dans les interfaces utilisateur avec de grands ensembles de données.
Utilisation d'Intl.Collator pour une comparaison efficace des chaînes
Intl.Collator crée un objet de comparaison réutilisable qui traite les paramètres de locale une seule fois :
const collator = new Intl.Collator("de");
const sorted = items.sort((a, b) => collator.compare(a, b));
L'instance du collator stocke la configuration de locale et les règles de comparaison. La méthode compare utilise ces règles précalculées pour chaque comparaison, éliminant la surcharge d'initialisation répétée.
Les améliorations de performance varient de 60% à 80% lors du tri de grands tableaux par rapport aux appels répétés de localeCompare.
Accéder directement à la méthode compare
Vous pouvez passer la méthode compare directement à sort :
const collator = new Intl.Collator("de");
const sorted = items.sort(collator.compare);
Cela fonctionne car compare est liée à l'instance du collator. La méthode reçoit deux chaînes et renvoie le résultat de la comparaison, correspondant à la signature attendue par Array.sort.
Comprendre les niveaux de sensibilité
L'option sensitivity contrôle quelles différences de caractères importent pendant la comparaison. Il existe quatre niveaux :
Sensibilité de base
La sensibilité de base ignore les accents et la casse :
const collator = new Intl.Collator("en", { sensitivity: "base" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // 0
console.log(collator.compare("a", "A")); // 0
console.log(collator.compare("a", "b")); // -1
Seules les lettres de base diffèrent. Ce niveau fonctionne bien pour la recherche approximative où les utilisateurs pourraient ne pas taper correctement les accents.
Sensibilité aux accents
La sensibilité aux accents prend en compte les accents mais ignore la casse :
const collator = new Intl.Collator("en", { sensitivity: "accent" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // -1
console.log(collator.compare("a", "A")); // 0
console.log(collator.compare("á", "A")); // 1
Les caractères accentués et non accentués diffèrent. Les versions majuscules et minuscules de la même lettre correspondent.
Sensibilité à la casse
La sensibilité à la casse prend en compte la casse mais ignore les accents :
const collator = new Intl.Collator("en", { sensitivity: "case" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // 0
console.log(collator.compare("a", "A")); // -1
console.log(collator.compare("á", "Á")); // -1
Les différences de casse sont importantes mais les accents sont ignorés. Ce niveau est moins courant en pratique.
Sensibilité aux variantes
La sensibilité aux variantes prend en compte toutes les différences :
const collator = new Intl.Collator("en", { sensitivity: "variant" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // -1
console.log(collator.compare("a", "A")); // -1
console.log(collator.compare("á", "Á")); // -1
C'est la valeur par défaut pour le tri. Chaque différence de caractère produit un résultat de comparaison distinct.
Choisir la sensibilité selon le cas d'utilisation
Différents scénarios nécessitent différents niveaux de sensibilité :
- Tri de listes : utiliser la sensibilité aux variantes pour maintenir un ordre strict
- Recherche de contenu : utiliser la sensibilité de base pour correspondre indépendamment des accents ou de la casse
- Filtrage d'options : utiliser la sensibilité aux accents lorsque la casse ne devrait pas importer
- Recherche sensible à la casse : utiliser la sensibilité à la casse lorsque les accents ne devraient pas importer
L'option usage fournit des paramètres de sensibilité par défaut pour les scénarios courants.
Utilisation de usage pour les modes de tri et de recherche
L'option usage optimise le comportement du collator pour le tri ou la recherche :
// Optimisé pour le tri
const sortCollator = new Intl.Collator("en", { usage: "sort" });
// Optimisé pour la recherche
const searchCollator = new Intl.Collator("en", { usage: "search" });
L'usage sort utilise par défaut la sensibilité aux variantes, garantissant que chaque différence produit un ordre cohérent. L'usage search optimise la recherche de correspondances, utilisant généralement une sensibilité plus souple.
Pour une recherche insensible à la casse et aux accents :
const collator = new Intl.Collator("en", {
usage: "search",
sensitivity: "base"
});
const items = ["Apple", "Äpfel", "Banana"];
const matches = items.filter(item =>
collator.compare(item, "apple") === 0
);
console.log(matches); // ["Apple"]
Ce modèle permet une correspondance approximative où les utilisateurs n'ont pas besoin de taper les caractères exacts.
Activation du tri numérique pour un ordre naturel
L'option numeric traite les nombres intégrés comme des valeurs numériques :
const collator = new Intl.Collator("en", { numeric: true });
const files = ["File1", "File10", "File2"];
console.log(files.sort(collator.compare));
// ["File1", "File2", "File10"]
Sans tri numérique, "File10" serait classé avant "File2" car la chaîne "10" commence par "1". Le tri numérique analyse les séquences de nombres et les compare mathématiquement.
Cela produit un ordre naturel qui correspond aux attentes humaines pour les noms de fichiers, les numéros de version et les listes numérotées.
Gestion des nombres décimaux avec le tri numérique
Le tri numérique présente une limitation avec les nombres décimaux :
const collator = new Intl.Collator("en", { numeric: true });
const values = ["1.5", "1.10", "1.2"];
console.log(values.sort(collator.compare));
// ["1.2", "1.5", "1.10"]
Le point décimal est traité comme une ponctuation, et non comme une partie du nombre. Chaque segment entre les ponctuations est trié séparément. Pour le tri des nombres décimaux, analysez les valeurs en nombres et utilisez une comparaison numérique.
Contrôle de l'ordre des majuscules avec caseFirst
L'option caseFirst détermine si les lettres majuscules ou minuscules sont triées en premier :
// Majuscules d'abord
const upperFirst = new Intl.Collator("en", { caseFirst: "upper" });
console.log(["a", "A", "b", "B"].sort(upperFirst.compare));
// ["A", "a", "B", "b"]
// Minuscules d'abord
const lowerFirst = new Intl.Collator("en", { caseFirst: "lower" });
console.log(["a", "A", "b", "B"].sort(lowerFirst.compare));
// ["a", "A", "b", "B"]
La valeur par défaut est false, qui utilise l'ordre par défaut de la locale. Cette option n'a aucun effet lorsque sensitivity est base ou accent car ces niveaux ignorent la casse.
Ignorer la ponctuation pendant la comparaison
L'option ignorePunctuation ignore les signes de ponctuation pendant la comparaison :
const collator = new Intl.Collator("en", { ignorePunctuation: true });
console.log(collator.compare("hello", "he-llo")); // 0
console.log(collator.compare("hello", "hello!")); // 0
Cette option est définie par défaut à true pour le thaï et à false pour les autres langues. Utilisez-la lorsque la ponctuation ne doit pas affecter l'ordre ou la correspondance des chaînes.
Spécification des types de collation pour les règles spécifiques aux langues
Certaines locales prennent en charge plusieurs types de collation pour des tris spécialisés :
// Tri chinois pinyin
const pinyin = new Intl.Collator("zh-CN-u-co-pinyin");
// Tri selon l'annuaire téléphonique allemand
const phonebook = new Intl.Collator("de-DE-u-co-phonebk");
// Regroupement d'emoji
const emoji = new Intl.Collator("en-u-co-emoji");
Le type de collation est spécifié dans la chaîne de locale en utilisant la syntaxe d'extension Unicode. Les types courants incluent :
pinyin: tri chinois par prononciation romaniséestroke: tri chinois par nombre de traitsphonebk: tri selon l'annuaire téléphonique allemandtrad: règles de tri traditionnelles pour certaines languesemoji: regroupe les emoji par catégorie
Vérifiez Intl.supportedValuesOf pour les types de collation disponibles dans votre environnement.
Réutilisation des instances de collator dans votre application
Créez des instances de collator une seule fois et réutilisez-les dans toute votre application :
// utils/collation.js
export const germanCollator = new Intl.Collator("de");
export const searchCollator = new Intl.Collator("en", {
sensitivity: "base"
});
export const numericCollator = new Intl.Collator("en", {
numeric: true
});
// Dans vos composants
import { germanCollator } from "./utils/collation";
const sorted = names.sort(germanCollator.compare);
Ce modèle maximise les performances et maintient un comportement de comparaison cohérent dans tout votre code.
Tri des tableaux d'objets par propriété
Utilisez le collator dans une fonction de comparaison qui accède aux propriétés d'objet :
const collator = new Intl.Collator("de");
const users = [
{ name: "Zoe" },
{ name: "Änder" },
{ name: "Ava" }
];
const sorted = users.sort((a, b) =>
collator.compare(a.name, b.name)
);
Cette approche fonctionne pour n'importe quelle structure d'objet. Extrayez les chaînes à comparer et passez-les au collator.
Comparaison des performances entre Intl.Collator et localeCompare
Intl.Collator offre de meilleures performances lors du tri de grands ensembles de données :
// Plus lent : recrée les paramètres de locale pour chaque comparaison
const slow = items.sort((a, b) => a.localeCompare(b, "de"));
// Plus rapide : réutilise les paramètres de locale précalculés
const collator = new Intl.Collator("de");
const fast = items.sort(collator.compare);
Pour les petits tableaux (moins de 100 éléments), la différence est négligeable. Pour les grands tableaux (milliers d'éléments), Intl.Collator peut être 60-80 % plus rapide.
Il existe une exception dans les navigateurs basés sur V8 comme Chrome. localeCompare dispose d'une optimisation pour les chaînes uniquement ASCII utilisant des tables de consultation. Lors du tri de chaînes purement ASCII, localeCompare peut avoir des performances comparables à Intl.Collator.
Savoir quand utiliser Intl.Collator par rapport à localeCompare
Utilisez Intl.Collator quand :
- Vous triez de grands tableaux (des centaines ou des milliers d'éléments)
- Vous effectuez des tris répétés (l'utilisateur bascule l'ordre de tri, listes virtuelles)
- Vous créez des utilitaires de comparaison réutilisables
- La performance est importante pour votre cas d'utilisation
Utilisez localeCompare quand :
- Vous faites des comparaisons ponctuelles
- Vous triez de petits tableaux (moins de 100 éléments)
- La simplicité prime sur les préoccupations de performance
- Vous avez besoin d'une comparaison en ligne sans configuration préalable
Les deux API prennent en charge les mêmes options et produisent des résultats identiques. La différence concerne uniquement la performance et l'organisation du code.
Vérification des options résolues
La méthode resolvedOptions renvoie les options réellement utilisées par le collator :
const collator = new Intl.Collator("de", { sensitivity: "base" });
console.log(collator.resolvedOptions());
// {
// locale: "de",
// usage: "sort",
// sensitivity: "base",
// ignorePunctuation: false,
// collation: "default",
// numeric: false,
// caseFirst: "false"
// }
Cela aide à déboguer le comportement de collation et à comprendre les valeurs par défaut. La locale résolue peut différer de la locale demandée si le système ne prend pas en charge la locale exacte.
Vérification de la prise en charge des locales
Vérifiez quelles locales sont prises en charge dans l'environnement actuel :
const supported = Intl.Collator.supportedLocalesOf(["de", "fr", "xx"]);
console.log(supported); // ["de", "fr"]
Les locales non prises en charge se replient sur la valeur par défaut du système. Cette méthode permet de détecter quand votre locale demandée n'est pas disponible.
Prise en charge par les navigateurs et les environnements
Intl.Collator est largement pris en charge depuis septembre 2017. Tous les navigateurs modernes et les versions de Node.js le prennent en charge. L'API fonctionne de manière cohérente dans tous les environnements.
Certains types de collation et options peuvent avoir une prise en charge limitée dans les navigateurs plus anciens. Testez les fonctionnalités critiques ou consultez les tableaux de compatibilité MDN si vous prenez en charge des environnements plus anciens.
Erreurs courantes à éviter
Ne créez pas un nouveau collator pour chaque comparaison :
// Incorrect : crée un collator à répétition
items.sort((a, b) => new Intl.Collator("de").compare(a, b));
// Correct : créer une fois, réutiliser
const collator = new Intl.Collator("de");
items.sort(collator.compare);
Ne supposez pas que le tri par défaut fonctionne pour le texte international :
// Incorrect : ne fonctionne pas pour les caractères non-ASCII
names.sort();
// Correct : utiliser un tri adapté à la locale
names.sort(new Intl.Collator("de").compare);
N'oubliez pas de spécifier la sensibilité pour la recherche :
// Incorrect : la sensibilité par défaut exige une correspondance exacte
const collator = new Intl.Collator("en");
items.filter(item => collator.compare(item, "apple") === 0);
// Correct : sensibilité de base pour une correspondance approximative
const collator = new Intl.Collator("en", { sensitivity: "base" });
items.filter(item => collator.compare(item, "apple") === 0);
Cas d'utilisation pratiques
Utilisez Intl.Collator pour :
- Trier le contenu généré par les utilisateurs (noms, titres, adresses)
- Implémenter des fonctionnalités de recherche et d'autocomplétion
- Construire des tableaux de données avec des colonnes triables
- Créer des listes filtrées et des options de menu déroulant
- Trier des noms de fichiers et des numéros de version
- Navigation alphabétique dans les listes de contacts
- Interfaces d'application multilingues
Toute interface qui affiche du texte trié pour les utilisateurs bénéficie d'une collation adaptée à la locale. Cela garantit que votre application semble native et correcte quelle que soit la langue de l'utilisateur.