DEV Community

Cover image for Zahlennormalisierung für internationale Daten: Ein praktischer Leitfaden
circobit
circobit

Posted on

Zahlennormalisierung für internationale Daten: Ein praktischer Leitfaden

Man exportiert eine Tabelle von einer deutschen Website. Die Umsatzspalte zeigt „1.234,56 €".

Man fügt es in Excel ein. Es wird zu „1.23456E" oder, schlimmer noch, zu einem Datum.

Willkommen beim internationalen Zahlenformat-Problem.

Das Kernproblem: Was bedeutet „1.234"?

In den USA und UK: 1.234 = eins Komma zwei drei vier (Dezimal)

In Deutschland, Spanien und den meisten Ländern Lateinamerikas: 1.234 = eintausendzweihundertvierunddreißig

Dieselben Zeichen. Völlig unterschiedliche Werte.

Beim Extrahieren von Daten aus internationalen Websites kann man nicht annehmen, welches Format vorliegt. Und wenn man falsch liegt, ist die Analyse um Größenordnungen daneben.

Die Drei-Stellen-Mehrdeutigkeit

Der schwierigste Fall: exakt drei Stellen nach einem Trennzeichen.

Eingabe US-Interpretation EU-Interpretation
1.234 1,234 (Dezimal) 1.234 (Tausender)
1,234 1.234 (Tausender) 1,234 (Dezimal)
1.234.567 Ungültig 1.234.567
1,234,567 1.234.567 Ungültig

Mit zwei Stellen danach ist es eindeutig Dezimal: „1.23" oder „1,23".
Mit vier+ Stellen danach ist es eindeutig Dezimal: „3.14159".
Mit drei Stellen? Kann beides sein.

Der Erkennungsalgorithmus

Hier ein heuristischer Ansatz, der die meisten Praxisfälle abdeckt:

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

  // Schritt 1: Währungssymbole, Prozente, Leerzeichen bereinigen
  let cleaned = v
    .replace(/ /g, " ")
    .replace(/^(USD|EUR|GBP|R\$|MXN)\s*/i, "")
    .replace(/[$€£¥₹₽₩]/g, "")
    .replace(/%/g, "")
    .replace(/\s+/g, "");

  // Schritt 2: Negative Vorzeichen behandeln
  const isNegative = cleaned.match(/^-/);
  if (isNegative) {
    cleaned = cleaned.substring(1).trim();
  }

  // Schritt 3: Nur Ziffern? Fertig
  if (/^\d+$/.test(cleaned)) {
    return isNegative ? `-${cleaned}` : cleaned;
  }

  // Schritt 4: Trennzeichen erkennen
  const hasComma = cleaned.includes(",");
  const hasDot = cleaned.includes(".");

  // Schritt 5: Heuristik anwenden
  let decimalSeparator = ".";
  let thousandsSeparator = ",";

  if (hasComma && hasDot) {
    // Beide vorhanden: das letzte ist das Dezimalzeichen
    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" → Dezimal
      decimalSeparator = ",";
    } else {
      // "1,234" oder "1,234,567" → Tausender
      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" oder "3.14159" → Dezimal
        decimalSeparator = ".";
      } else {
        // "1.234" → TAUSENDER (pragmatische Wahl für Tabellen)
        decimalSeparator = null;
        thousandsSeparator = ".";
      }
    } else {
      // Mehrere Punkte → Tausender
      decimalSeparator = null;
      thousandsSeparator = ".";
    }
  }

  // Schritt 6: Tausendertrennzeichen entfernen
  if (thousandsSeparator) {
    cleaned = cleaned.replace(new RegExp(`\\${thousandsSeparator}`, "g"), "");
  }

  // Schritt 7: Dezimalzeichen zu Punkt normalisieren
  if (decimalSeparator && decimalSeparator !== ".") {
    cleaned = cleaned.replace(decimalSeparator, ".");
  }

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

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

Warum drei Stellen = Tausender

Die Schlüsselentscheidung: Wenn wir exakt drei Stellen nach einem einzelnen Trennzeichen sehen (wie „1.234"), interpretieren wir es als Tausender, nicht als Dezimal.

Warum? In HTML-Tabellen:

  • Finanzdaten mit Tausendern sind extrem häufig: $1.234, €1.234
  • Dezimalzahlen mit exakt drei Stellen sind in der Praxis selten
  • Wissenschaftliche Daten mit drei Dezimalstellen (wie „3.141") werden meist als „3.14159" oder einfach „3.14" geschrieben

Diese Heuristik ist ein pragmatischer Kompromiss, der für die Mehrheit realer Tabellen funktioniert.

Die vollständige Format-Matrix

Eingabe Interpretation Normalisierte Ausgabe
1.234,56 EU-Dezimal 1234.56
1,234.56 US-Dezimal 1234.56
1.234.567,89 EU-Tausender + Dezimal 1234567.89
1,234,567.89 US-Tausender + Dezimal 1234567.89
1.234 Tausender 1234
1,234 Tausender 1234
3.14 Dezimal 3.14
3,14 Dezimal 3.14
3.14159 Dezimal (4+ Stellen) 3.14159
$ 1.200,50 Währung + EU 1200.50
-5.000 Negative Tausender -5000
12.5% Prozent 12.5

Währungscodes behandeln

Internationale Daten kommen mit Währungspräfixen und -suffixen. Diese zuerst bereinigen:

// Währungscodes VOR Symbolen entfernen
.replace(/^(USD|EUR|GBP|JPY|CHF|CAD|AUD|CNY|INR|BRL|R\$|MXN|KRW)\s*/i, "")
// Dann Symbole entfernen
.replace(/[$€£¥₹₽₩₪฿₫₴₦]/g, "")
Enter fullscreen mode Exit fullscreen mode

Die Reihenfolge ist wichtig: „R$" (Brasilianischer Real) enthält „$", also verhindert das vorherige Entfernen der Währungscodes partielle Treffer.

Wenn die Heuristik versagt

Keine Heuristik ist perfekt. Man bekommt falsche Ergebnisse bei:

  1. Wissenschaftliche Daten mit exakt 3 Dezimalstellen: „3.141" wird zu „3141"
  2. Preise unter 10 € mit 3 Dezimalstellen: „1.234 €" wird zu „1234 €"
  3. Gemischte Formate in einer Spalte: Manche Zeilen EU, manche US

Für Fall 3 braucht man spaltenweite Formaterkennung:

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"; // Zellweise Heuristik verwenden
}
Enter fullscreen mode Exit fullscreen mode

Export-Profile für verschiedene Regionen

Wenn man das Herkunftsland kennt, kann man die Mehrdeutigkeit komplett vermeiden, indem man regionsspezifische Profile verwendet:

  • Europäisches Format: Nimmt Komma als Dezimaltrennzeichen an, verwendet Semikolon als CSV-Trennzeichen
  • US/UK-Format: Nimmt Punkt als Dezimaltrennzeichen an, verwendet Komma als CSV-Trennzeichen

HTML Table Exporter enthält vordefinierte Profile für beide Formate, plus spezialisierte Profile für Tools wie Pandas und DuckDB.

Häufige Fallstricke

Präzision nicht verlieren

// Falsch: verliert Präzision bei großen Zahlen
const num = parseFloat("12345678901234567890");
// 12345678901234567000 (JavaScript-Limit)

// Besser: als String behalten bis zur finalen Berechnung
const cleaned = normalizeNumberString(value);
// Erst parseFloat verwenden, wenn man rechnen muss
Enter fullscreen mode Exit fullscreen mode

Auf HTML-Entities achten

Webtabellen enthalten manchmal &nbsp; (geschütztes Leerzeichen) in Zahlen:

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

Original beibehalten, wenn unsicher

Wenn der Wert nicht wie eine Zahl aussieht, unverändert zurückgeben:

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

Besser „N/A" als „N/A" belassen, als zu versuchen es zu parsen.

Zusammenfassung

Szenario Erkennung Hinweise
Sowohl . als auch , Letztes = Dezimal Universal
Nur Komma, ≤2 Stellen danach Dezimal „1,23"
Nur Komma, 3+ Stellen danach Tausender „1,234"
Nur Punkt, ≤2 oder 4+ Stellen Dezimal „1.23", „3.14159"
Nur Punkt, exakt 3 Stellen Tausender „1.234"

Der Drei-Stellen-Fall ist der pragmatische Kompromiss. Er funktioniert für die meisten realen Daten. Im Zweifelsfall ein Export-Profil verwenden, das zur Quellregion passt.

Für mehr zum Kopieren von Daten aus Websites nach Excel ohne Formatierungsprobleme, siehe unseren Leitfaden zur besten Chrome-Erweiterung zum Kopieren von Tabellen nach Excel.


Saubere Zahlenexporte ohne Ratespiel? Erfahren Sie mehr auf gauchogrid.com/de/html-table-exporter oder probieren Sie es kostenlos im Chrome Web Store.

Top comments (0)