Vous exportez un tableau depuis un site allemand. La colonne revenus affiche « 1.234,56 € ».
Vous le collez dans Excel. Ça devient « 1.23456E » ou, pire, une date.
Bienvenue dans le problème des formats numériques internationaux.
Le Problème Central : Que Signifie « 1.234 » ?
Aux États-Unis et au Royaume-Uni : 1.234 = un virgule deux trois quatre (décimal)
En Allemagne, en Espagne et dans la plupart de l'Amérique latine : 1.234 = mille deux cent trente-quatre
Mêmes caractères. Valeurs complètement différentes.
Quand vous extrayez des données de sites internationaux, vous ne pouvez pas supposer quel format est utilisé. Et se tromper signifie que votre analyse est décalée de plusieurs ordres de grandeur.
L'Ambiguïté des Trois Chiffres
Le cas le plus difficile est exactement trois chiffres après un séparateur.
| Entrée | Interprétation US | Interprétation EU |
|---|---|---|
| 1.234 | 1,234 (décimal) | 1 234 (milliers) |
| 1,234 | 1 234 (milliers) | 1,234 (décimal) |
| 1.234.567 | Invalide | 1 234 567 |
| 1,234,567 | 1 234 567 | Invalide |
Avec deux chiffres après, c'est clairement décimal : « 1.23 » ou « 1,23 ».
Avec quatre chiffres ou plus, c'est clairement décimal : « 3.14159 ».
Avec trois chiffres ? Ça peut être l'un ou l'autre.
L'Algorithme de Détection
Voici une approche heuristique qui gère la plupart des cas réels :
function normalizeNumberString(value) {
if (typeof value !== "string") return value;
const v = value.trim();
if (!v || !/[0-9]/.test(v)) return value;
// Étape 1 : Nettoyer symboles monétaires, pourcentages, espaces
let cleaned = v
.replace(/ /g, " ")
.replace(/^(USD|EUR|GBP|R\$|MXN)\s*/i, "")
.replace(/[$€£¥₹₽₩]/g, "")
.replace(/%/g, "")
.replace(/\s+/g, "");
// Étape 2 : Gérer les signes négatifs
const isNegative = cleaned.match(/^-/);
if (isNegative) {
cleaned = cleaned.substring(1).trim();
}
// Étape 3 : Chiffres purs ? C'est terminé
if (/^\d+$/.test(cleaned)) {
return isNegative ? `-${cleaned}` : cleaned;
}
// Étape 4 : Détecter les séparateurs
const hasComma = cleaned.includes(",");
const hasDot = cleaned.includes(".");
// Étape 5 : Appliquer l'heuristique
let decimalSeparator = ".";
let thousandsSeparator = ",";
if (hasComma && hasDot) {
// Les deux présents : le dernier est le décimal
const lastComma = cleaned.lastIndexOf(",");
const lastDot = cleaned.lastIndexOf(".");
if (lastComma > lastDot) {
decimalSeparator = ",";
thousandsSeparator = ".";
}
} else if (hasComma && !hasDot) {
const parts = cleaned.split(",");
if (parts.length === 2 && parts[1].length <= 2) {
// "1,23" → décimal
decimalSeparator = ",";
} else {
// "1,234" ou "1,234,567" → milliers
decimalSeparator = null;
thousandsSeparator = ",";
}
} else if (hasDot && !hasComma) {
const parts = cleaned.split(".");
if (parts.length === 2) {
const afterDot = parts[1];
if (afterDot.length <= 2 || afterDot.length >= 4) {
// "1.23" ou "3.14159" → décimal
decimalSeparator = ".";
} else {
// "1.234" → MILLIERS (choix pragmatique pour les tableaux)
decimalSeparator = null;
thousandsSeparator = ".";
}
} else {
// Points multiples → milliers
decimalSeparator = null;
thousandsSeparator = ".";
}
}
// Étape 6 : Supprimer les séparateurs de milliers
if (thousandsSeparator) {
cleaned = cleaned.replace(new RegExp(`\\${thousandsSeparator}`, "g"), "");
}
// Étape 7 : Normaliser le décimal en point
if (decimalSeparator && decimalSeparator !== ".") {
cleaned = cleaned.replace(decimalSeparator, ".");
}
// Étape 8 : Valider
const num = Number(cleaned);
if (!Number.isFinite(num)) return value;
return isNegative ? `-${cleaned}` : cleaned;
}
Pourquoi Trois Chiffres = Milliers
La décision clé : quand on voit exactement trois chiffres après un seul séparateur (comme « 1.234 »), on interprète comme des milliers, pas comme un décimal.
Pourquoi ? Dans les tableaux HTML :
- Les données financières avec des milliers sont extrêmement courantes : 1.234 $, 1.234 €
- Les décimaux avec exactement trois chiffres sont rares en pratique
- Les données scientifiques à trois décimales (comme « 3.141 ») sont généralement écrites « 3.14159 » ou simplement « 3.14 »
Cette heuristique est un compromis pragmatique qui fonctionne pour la majorité des tableaux réels.
La Matrice Complète des Formats
| Entrée | Interprétation | Sortie Normalisée |
|---|---|---|
| 1.234,56 | Décimal EU | 1234.56 |
| 1,234.56 | Décimal US | 1234.56 |
| 1.234.567,89 | Milliers + décimal EU | 1234567.89 |
| 1,234,567.89 | Milliers + décimal US | 1234567.89 |
| 1.234 | Milliers | 1234 |
| 1,234 | Milliers | 1234 |
| 3.14 | Décimal | 3.14 |
| 3,14 | Décimal | 3.14 |
| 3.14159 | Décimal (4+ chiffres) | 3.14159 |
| $ 1.200,50 | Devise + EU | 1200.50 |
| -5.000 | Milliers négatifs | -5000 |
| 12.5% | Pourcentage | 12.5 |
Gérer les Codes Devises
Les données internationales arrivent avec des préfixes et suffixes de devises. Nettoyez-les d'abord :
// Supprimer les codes devises AVANT les symboles
.replace(/^(USD|EUR|GBP|JPY|CHF|CAD|AUD|CNY|INR|BRL|R\$|MXN|KRW)\s*/i, "")
// Puis supprimer les symboles
.replace(/[$€£¥₹₽₩₪฿₫₴₦]/g, "")
L'ordre compte : « R$ » (Real brésilien) contient « $ », donc supprimer les codes devises en premier évite les correspondances partielles.
Quand l'Heuristique Échoue
Aucune heuristique n'est parfaite. Vous obtiendrez des résultats incorrects quand :
- Données scientifiques avec exactement 3 décimales : « 3.141 » devient « 3141 »
- Prix sous 10 $ avec 3 décimales : « $1.234 » devient « $1234 »
- Formats mixtes dans une colonne : Certaines lignes EU, d'autres US
Pour le cas 3, vous avez besoin d'une détection au niveau de la colonne :
function detectColumnFormat(values) {
let euIndicators = 0;
let usIndicators = 0;
for (const v of values) {
if (/\d\.\d{3},\d{2}$/.test(v)) euIndicators++;
if (/\d,\d{3}\.\d{2}$/.test(v)) usIndicators++;
}
if (euIndicators > usIndicators) return "eu";
if (usIndicators > euIndicators) return "us";
return "auto"; // Utiliser l'heuristique par cellule
}
Profils d'Export pour Différentes Régions
Quand vous connaissez le pays source, vous pouvez éviter toute ambiguïté en utilisant des profils spécifiques à la région :
- Format européen : Suppose la virgule comme séparateur décimal, utilise le point-virgule comme délimiteur CSV
- Format US/UK : Suppose le point comme séparateur décimal, utilise la virgule comme délimiteur CSV
HTML Table Exporter inclut des profils prédéfinis pour les deux formats, plus des profils spécialisés pour des outils comme Pandas et DuckDB.
Pièges Courants
Ne Pas Perdre la Précision
// Faux : perd la précision sur les grands nombres
const num = parseFloat("12345678901234567890");
// 12345678901234567000 (limite JavaScript)
// Mieux : garder en chaîne jusqu'au calcul final
const cleaned = normalizeNumberString(value);
// Ne faire parseFloat que quand le calcul est nécessaire
Attention aux Entités HTML
Les tableaux web contiennent parfois (espace insécable) dans les nombres :
// "1 234 567" devrait devenir "1234567"
.replace(/ /g, " ")
.replace(/\s+/g, "")
Préserver l'Original en Cas de Doute
Si la valeur ne ressemble pas à un nombre, retournez-la inchangée :
if (!/[0-9]/.test(v)) return value;
// ...
if (!Number.isFinite(num)) return value;
Mieux vaut laisser « N/A » tel quel que d'essayer de le parser.
Résumé
| Scénario | Détection | Notes |
|---|---|---|
| . et , présents | Le dernier = décimal | Universel |
| Virgule seule, ≤2 chiffres après | Décimal | « 1,23 » |
| Virgule seule, 3+ chiffres après | Milliers | « 1,234 » |
| Point seul, ≤2 ou 4+ chiffres | Décimal | « 1.23 », « 3.14159 » |
| Point seul, exactement 3 chiffres | Milliers | « 1.234 » |
Le cas des trois chiffres est le compromis pragmatique. Ça fonctionne pour la plupart des données réelles. En cas de doute, utilisez un profil d'export correspondant à la région source.
Pour en savoir plus sur la copie de données depuis des sites web vers Excel sans problèmes de formatage, consultez notre guide sur la meilleure extension Chrome pour copier des tableaux dans Excel.
Besoin d'exports de nombres propres sans devinettes ? En savoir plus sur gauchogrid.com/fr/html-table-exporter ou essayez-le gratuitement sur le Chrome Web Store.
Top comments (0)