site logo

Validace čísel ve formuláři

Jak ověřit správnost čísla ve webovém formuláři s ohledem na národní prostředí a další problémy validace čísel jsou popsány v tomto článku. Validaci čísel provádíme proto abychom zabránili chybám na serveru při převodu na číselný datový typ a pokusu uložit do databáze nesprávný typ dat.

Do webového formuláře jsou číselné údaje zapsány jako text (řetězec, string) a stejně tak jsou formulářová data odeslána na server jako řetězce. Jako validní číselný údaj lze považovat takový zápis, kdy klient i server vyhodnotí údaj jako platný a navíc je ve shodě s datovým typem položky databáze do které je číslo uloženo.

Anglo-americký zápis plovoucího čísla (stejně jako JavaScript) používá pro oddělovač desetinné části čísla znak tečka, zatímco české národní zvyklosti nám předepisují použití desetinné čárky. Znak čárka je někdy používán v anglo-amerických zemích pro oddělení skupiny řádů (tisíce). Naše národní zvyklosti pro tento případ doporučují znak mezera. JavaScript v matematických funkcích pro přetypování řetězce na číselnou hodnotu vždy vyžaduje použití desetinné tečky.

Správná validace čísla v browseru s ohledem na národní zvyklosti jazykové verze aplikace je nutná, nikoli však postačující. Důležitá je správná validace na serveru, tentokrát s ohledem na platné národní prostředí serveru tak, aby přetypování proběhlo bezchybně, jinými slovy zajistit správný oddělovač desetinných míst. Dále bychom měli testovat číselný rozsah podle použitých datových typů v databázi tak, aby nedošlo k chybě přetečení. Mějte na paměti, že uložením velkého kladného celého čísla můžete někdy dosáhnout přetečení do rozsahu záporných čísel.

Při zadávání numerických dat z numerické části desktopové klávesnice je desetinný odělovač závislý na aktuálním nastavení jazyka klávesnice. Běžně máme zapnutou českou klávesnici a desetinná čísla se oddělují znakem ",". Pokud přepneme na angličtinu, význam klávesy pro desetinný oddělovač se změní na desetinnou tečku. Ani uživatelé nemají vždy jasno, který znak použít. Správná validace by měla ošetřit použití obou znaků.

typ čísla hodnota výsledek
celé číslo
desetinné číslo
libovolné číslo

Testovací číselný formulář a skripty

Do miniformuláře zapíšete čísla, kliknutím na tlačítko spustíte validační skript pro ověření správnosti všech zapsaných údajů. JavaScript vyhodnotí číselné údaje a výsledek oznámí v pravém sloupci formuláře.

Při validaci čísel postupujeme následovně: údaj z formuláře, který je vždy řetězec znaků (string) převedeme na typ numeric pomocí dvou různých metod a obě numerické hodnoty porovnáme. Když hodnoty nejsou shodné, výchozí číselný údaj je chybný.

Některé validační metody používají jeden převod na typ numeric, následovaný převodem zpět na typ string, který je porovnán s výchozím textovým řetězcem. Taková validace funguje do té doby, než někdo zapomene ve formulářovém poli bílý znak před, nebo za číslem. Protože taková mezera není v textboxu vidět, ohlášená chyba se hledá velmi těžko. Existují ještě další metody pro validaci čísel např. pomocí regulárních výrazů, nebo funkce isNaN(), ty zde nejsou popsány.


// ---------- validace celého čísla -----------
function isInteger(value) {
  if(value == "") return false;
  if(parseInt(value, 10) != (value*1)) return false;
  return true;
}

První ukázka kódu pro převod textového řetězce na číslo je pomocí funkce parseInt(). Převod je ukončen na konci řetězce, nebo při nalezení nečíselného znaku. Druhý parametr funkce určuje číselnou soustavu ve které má probíhat převod. Vynechání parametru číselné soustavy by někdy mohlo vést k chybné validaci (např. čísla začínající nulou jsou považována za oktalová).

Dále provedeme jednoduchou matematickou operaci, při které se nezmění původní hodnota parametru, ale provede se přetypování na typ numeric. K tomu lze použít násobení jedničkou, dělení jedničkou, nebo odečtení nuly. Pozor nulu nejde přičítat. Znak plus se interpretuje jako sečítání textových řetězců, v tomto případě by znamenalo násobení deseti. Oba výsledky, nyní datového typu numeric, porovnáme. Pokud jsou shodné, textový parametr je převoditelný na číselný údaj a může být považován za validní číslo.


// ---------- validace desetinného čísla -------------
function isFloat(value) {
  if(value == "") return false;
  value = value.replace(/,/, '.');
  if(parseFloat(value) != (value*1)) return false;
  return true;
}

Druhá ukázka kódu je pro čísla s plovoucí čárkou. Nejdříve testujeme, zda řetězec není prázdný. Zachytíme tak případné chyby JavaScriptu ve starších browserech. Runtime chyba v JavaScriptu totiž v browserech IE způsobí přerušení validace (a návrat z validační funkce s hodnotu true). Formulář je pak odeslán jako by byl validní, nebo jako by byl vypnutý JavaScript. Pak je ovšem validace zcela zbytečná.

Druhý řádek sjednotí decimální znak tak, aby byl řetězec srozumitelný pro JavaScript. Případná decimální čárka je nahrazena decimální tečkou. Původní řetězec v textboxu zůstane nezměněn a v původním tvaru bude také odeslán na server jako součást formuláře. Proto podobné sjednocení decimálního znaku musíme provést i na serveru, tentokrát s ohledem na národní zvyklosti databáze, tedy zda je očekávána desetinná tečka nebo čárka.

Dále funkce probíhá stejně jako v předchozí ukázce jen s rozdílem použité převodní funkce parseFloat(). Tato funkce nevyžaduje parametr číselné soustavy, převod probíhá vždy v desítkové soustavě.


// ---------- validace libovolného čísla -------------
function isNumber(value) {
  if(value == "") return false;
  value = value.replace(/ /gi, "");
  value = value.replace(/,/, '.');
  oneDeci = false;
  for (var i = 0; i < value.length; i++) {
    var oneChar = value.charAt(i);
    if (i == 0 && oneChar == "-") {
      continue;
    }
    if (oneChar == "." && !oneDeci) {
      oneDeci = true;
      continue
    }
    if (oneChar < "0" || oneChar > "9") {
      return false
    }
  }
  return true;
}

Poslední ukázka je poněkud rozdílný způsob validace číselného údaje. Neprovádí se převod na datový typ numeric, ale testují se přípustné znaky. Druhý řádek funkce vymaže všechny případné mezery ze vstupního řetězce. Další řádek provede eventuální záměnu desetinného znaku čárka za tečku. Na čtvrtém řádku kódu resetujeme příznak výskytu desetinného znaku.

Upravený řetězec procházíme znak po znaku a provádíme testy. První znak může být záporné znaménko. Dále je test na výskyt desetinné tečky, která může být v řetězci pouze jedenkrát. Ostatní znaky mohou být jen číslice.

Testované číslo může mít oddělené skupiny řádů mezerou a může být použita desetinná tečka nebo čárka. Nelze použít znaménko plus pro kladná čísla a anglo-americký způsob oddělení skupiny řádů čárkou. Ukázka je vhodná jako základ pro další experimenty s validačními funkcemi. Velmi často jsou totiž kladeny specifické požadavky na platnost čísla a validační funkci je potřeba upravit.

Je smutnou pravdou, že poslední ukázku funkce by bylo možné nahradit vestavěnou funkcí IsNumeric() ve VBScriptu, podobně jako validace datumu pomocí VBScriptu popsaná v minulém článku. Užití JavaScriptu pro validaci není příliš efektivní, ale jediné možné. V žádném případě zde použití VBScriptu nedoporučuji a to ani na intranetu.

Validace čísel a výpočty

Mít validní čísla ve formuláři ještě neznamená, že formulář je vyplněn správně. Uvedu příklad validace dvou čísel udávající váhu brutto a netto. Předpokládáme, že váha brutto je větší, nanejvýš stejná jako váha netto. V opačném případě došlo k prohození údajů. Na intranetu který pracuje s výrobními, technologickými, nebo laboratorními daty najdeme celou řadu podobných případů kontroly vnitřní vazby číselných údajů.

Na příkladu porovnání dvou desetinných čísel si ukážeme některé záludnosti při kontrole vnitřní vazby čísel. Předpokládejme že obě vstupní pole obsahují platnou hodnotu váhy, tedy prošla validací pomocí výše popsané funkce isFloat().


// ---------- porovnání desetinných čísel -------------
function compareFloat(num1, num2) {
  brutto = num1.replace(/,/, '.');
  netto  = num2.replace(/,/, '.');
  if(parseFloat(netto) > parseFloat(brutto)) return false;
  return true;
}

Když textové pole s číselným údajem obsahuje desetinnou čárku, funkce parseFloat() bez varování odřízne desetinnou část čísla. Proto nejdříve nahradíme desetinné čárky desetinnou tečkou. Takovému zápisu již bude JavaScript rozumět. Číselná pole formuláře tak mohou obsahovat desetinnou čárku, nebo tečku a vyhodnocení proběhne správně.

Některé matematické operace (násobení, dělení) provedou automatické přetypování operandů na číselný typ. Jiné operace (sečítání, porovnání) jsou závislé na typu operandů. Proto přetypujeme oba řetězce na číselný typ a teprve pak porovnáme jejich binární hodnoty. Výsledek porovnání řetězců je ve někdy stejný jako číselné porovnání, ale jen tehdy, když oba řetězce mají stejný počet celých i desetinných číslic. Proto vždy přetypujeme na číselný typ.

updated 22.01.2010