DEV Community

Cover image for Getalnormalisatie voor Internationale Data: Een Praktische Gids
circobit
circobit

Posted on

Getalnormalisatie voor Internationale Data: Een Praktische Gids

Je exporteert een tabel van een Duitse website. De omzetkolom toont "1.234,56 €".

Je plakt het in Excel. Het wordt "1.23456E" of, erger nog, een datum.

Welkom bij het internationale getalnotatie-probleem.

Het Kernprobleem: Wat Betekent "1.234"?

In de VS en het VK: 1.234 = één komma twee drie vier (decimaal)

In Duitsland, Spanje en het grootste deel van Latijns-Amerika: 1.234 = duizend tweehonderdvierendertig

Dezelfde tekens. Totaal verschillende waarden.

Bij het extraheren van data van internationale websites kun je niet aannemen met welk formaat je te maken hebt. En als je het verkeerd hebt, zit je er met ordes van grootte naast.

De Drie-Cijfer-Ambiguïteit

Het lastigste geval is precies drie cijfers na een scheidingsteken.

Invoer VS-Interpretatie EU-Interpretatie
1.234 1.234 (decimaal) 1.234 (duizendtallen)
1,234 1.234 (duizendtallen) 1.234 (decimaal)
1.234.567 Ongeldig 1.234.567
1,234,567 1.234.567 Ongeldig

Met twee cijfers erna is het duidelijk decimaal: "1.23" of "1,23".
Met vier+ cijfers erna is het duidelijk decimaal: "3.14159".
Met drie cijfers? Kan allebei zijn.

Het Detectie-algoritme

Hier is een heuristische aanpak die de meeste real-world gevallen afhandelt:

function normalizeNumberString(value) {
  if (typeof value !== "string") return value;
  const v = value.trim();
  if (!v || !/[0-9]/.test(v)) return value;

  // Stap 1: Verwijder valutasymbolen, percentages, witruimte
  let cleaned = v
    .replace(/ /g, " ")
    .replace(/^(USD|EUR|GBP|R\$|MXN)\s*/i, "")
    .replace(/[$€£¥₹₽₩]/g, "")
    .replace(/%/g, "")
    .replace(/\s+/g, "");

  // Stap 2: Verwerk mintekens
  const isNegative = cleaned.match(/^-/);
  if (isNegative) {
    cleaned = cleaned.substring(1).trim();
  }

  // Stap 3: Alleen cijfers? Dan zijn we klaar
  if (/^\d+$/.test(cleaned)) {
    return isNegative ? `-${cleaned}` : cleaned;
  }

  // Stap 4: Detecteer scheidingstekens
  const hasComma = cleaned.includes(",");
  const hasDot = cleaned.includes(".");

  // Stap 5: Pas heuristiek toe
  let decimalSeparator = ".";
  let thousandsSeparator = ",";

  if (hasComma && hasDot) {
    // Beide aanwezig: de laatste is het decimaalteken
    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" → decimaal
      decimalSeparator = ",";
    } else {
      // "1,234" of "1,234,567" → duizendtallen
      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" of "3.14159" → decimaal
        decimalSeparator = ".";
      } else {
        // "1.234" → DUIZENDTALLEN (pragmatische keuze voor tabellen)
        decimalSeparator = null;
        thousandsSeparator = ".";
      }
    } else {
      // Meerdere punten → duizendtallen
      decimalSeparator = null;
      thousandsSeparator = ".";
    }
  }

  // Stap 6: Verwijder duizendtallenscheidingstekens
  if (thousandsSeparator) {
    cleaned = cleaned.replace(new RegExp(`\\${thousandsSeparator}`, "g"), "");
  }

  // Stap 7: Normaliseer decimaal naar punt
  if (decimalSeparator && decimalSeparator !== ".") {
    cleaned = cleaned.replace(decimalSeparator, ".");
  }

  // Stap 8: Valideer
  const num = Number(cleaned);
  if (!Number.isFinite(num)) return value;

  return isNegative ? `-${cleaned}` : cleaned;
}
Enter fullscreen mode Exit fullscreen mode

Waarom Drie Cijfers = Duizendtallen

De kernbeslissing: wanneer we precies drie cijfers na één scheidingsteken zien (zoals "1.234"), interpreteren we het als duizendtallen, niet als decimaal.

Waarom? In HTML-tabellen:

  • Financiële data met duizendtallen komt extreem vaak voor: $1.234, €1.234
  • Decimalen met precies drie cijfers zijn in de praktijk zeldzaam
  • Wetenschappelijke data met drie decimalen (zoals "3.141") wordt meestal geschreven als "3.14159" of gewoon "3.14"

Deze heuristiek is een pragmatische afweging die werkt voor het overgrote deel van real-world tabellen.

De Volledige Formaatmatrix

Invoer Interpretatie Genormaliseerde Output
1.234,56 EU decimaal 1234.56
1,234.56 VS decimaal 1234.56
1.234.567,89 EU duizendtallen + decimaal 1234567.89
1,234,567.89 VS duizendtallen + decimaal 1234567.89
1.234 Duizendtallen 1234
1,234 Duizendtallen 1234
3.14 Decimaal 3.14
3,14 Decimaal 3.14
3.14159 Decimaal (4+ cijfers) 3.14159
$ 1.200,50 Valuta + EU 1200.50
-5.000 Negatief duizendtallen -5000
12.5% Percentage 12.5

Omgaan met Valutacodes

Internationale data komt met valutaprefixen en -suffixen. Verwijder ze eerst:

// Verwijder valutacodes VOOR symbolen
.replace(/^(USD|EUR|GBP|JPY|CHF|CAD|AUD|CNY|INR|BRL|R\$|MXN|KRW)\s*/i, "")
// Verwijder daarna symbolen
.replace(/[$€£¥₹₽₩₪฿₫₴₦]/g, "")
Enter fullscreen mode Exit fullscreen mode

Volgorde is belangrijk: "R$" (Braziliaanse Real) bevat "$", dus het eerst verwijderen van valutacodes voorkomt gedeeltelijke matches.

Wanneer de Heuristiek Faalt

Geen heuristiek is perfect. Je krijgt onjuiste resultaten wanneer:

  1. Wetenschappelijke data met precies 3 decimalen: "3.141" wordt "3141"
  2. Prijzen onder $10 met 3 decimalen: "$1.234" wordt "$1234"
  3. Gemengde formaten in één kolom: Sommige rijen EU, sommige rijen VS

Voor geval 3 heb je kolomniveau-formaatdetectie nodig:

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"; // Gebruik per-cel heuristiek
}
Enter fullscreen mode Exit fullscreen mode

Exportprofielen voor Verschillende Regio's

Als je het bronland kent, kun je de ambiguïteit volledig vermijden door regiospecifieke profielen te gebruiken:

  • Europees formaat: Neemt de komma als decimaalteken, gebruikt puntkomma als CSV-scheidingsteken
  • VS/VK-formaat: Neemt de punt als decimaalteken, gebruikt komma als CSV-scheidingsteken

HTML Table Exporter bevat vooraf ingestelde profielen voor beide formaten, plus gespecialiseerde profielen voor tools zoals Pandas en DuckDB.

Veelvoorkomende Valkuilen

Verlies Geen Precisie

// Fout: verliest precisie bij grote getallen
const num = parseFloat("12345678901234567890");
// 12345678901234567000 (JavaScript-limiet)

// Beter: bewaar als string tot de laatste berekening
const cleaned = normalizeNumberString(value);
// Gebruik pas parseFloat wanneer je echt moet rekenen
Enter fullscreen mode Exit fullscreen mode

Let op HTML-Entiteiten

Webtabellen bevatten soms &nbsp; (niet-afbrekende spatie) binnen getallen:

// "1&nbsp;234&nbsp;567" moet "1234567" worden
.replace(/&nbsp;/g, " ")
.replace(/\s+/g, "")
Enter fullscreen mode Exit fullscreen mode

Bewaar het Origineel bij Twijfel

Als de waarde er niet uitziet als een getal, retourneer het dan ongewijzigd:

if (!/[0-9]/.test(v)) return value;
// ...
if (!Number.isFinite(num)) return value;
Enter fullscreen mode Exit fullscreen mode

Beter om "N.v.t." als "N.v.t." te laten dan te proberen het te parsen.

Samenvatting

Scenario Detectie Opmerkingen
Zowel . als , Laatste = decimaal Universeel
Alleen komma, ≤2 cijfers erna Decimaal "1,23"
Alleen komma, 3+ cijfers erna Duizendtallen "1,234"
Alleen punt, ≤2 of 4+ cijfers Decimaal "1.23", "3.14159"
Alleen punt, precies 3 cijfers Duizendtallen "1.234"

Het drie-cijfer-geval is de pragmatische afweging. Het werkt voor de meeste real-world data. Bij twijfel, gebruik een exportprofiel dat overeenkomt met je bronregio.

Lees voor meer over het kopiëren van data van websites naar Excel onze gids over de beste Chrome-extensie om tabellen naar Excel te kopiëren.


Wil je schone getalexporten zonder giswerk? Meer informatie op gauchogrid.com/nl/html-table-exporter of probeer het gratis in de Chrome Web Store.

Top comments (0)