Regulární výraz pro kontrolu čísla

Školení, která pořádám

Regulární výraz pro kontrolu čísla je asi to nejjednodušší, co se dá vymyslet, řeknete si možná. Jednoduché [0-9]+ problém přeci vyřeší… Tak jednoduché to ale není.

Jednak je potřeba pamatovat na to, že v řetězci už nesmí být nic jiného. V některých případech také vadí úvodní nuly (např. místo 010 se do databáze uloží 10). Správný regulární výraz pro kontrolu nezáporného celého čísla tedy je ^(0|[1-9][0-9]*)$.

S desetinnými a zápornými čísly se situace komplikuje. Vedle případného znaménka musíme zachytit i desetinnou tečku: ^-?(0|[1-9][0-9]*)(\.[0-9]+)?$. Pravostranné nuly obvykle nevadí. Pokud nám nevadí ani ty levostranné, lze použít trik. Pokud bychom chtěli povolit i zkrácený zápis .123, tak bude nejjednodušší použít aserci: ^-?(0|[1-9][0-9]*|(?=\.))(\.[0-9]+)?$

Jakub Vrána, Řešení problému, 7.9.2009, diskuse: 10 (nové: 0)

Diskuse

Jakub:

V tom posledním výrazu je myslím překlep, místo = za druhým otazníkem, by mělo být -, ne?

ikona Jakub Vrána OpenID:

Ne. (?= je lookahead possitive assertion, viz http://www.php.net/manual/en/regexp.reference.assertions.php. Podívá se, co následuje, aniž by to požrala.

bukaJ:

Jo, tak s pochopením asercí bojuju neustále :-(

ikona David Grudl:

Ve kterých případech vadí úvodní nuly?

ikona Jakub Vrána OpenID:

V žádné běžné situaci.

1. PHP vyhodnocuje číselný literál začínající úvodní nulou jako osmičkové číslo, to bychom ale museli vstup od uživatele poslat třeba evalu, což ani po kontrole nikdo soudný neudělá.

2. Když se rozhodujeme, jestli databázi poslat data jako číslo nebo jako řetězec, tak poslání 0123 jako číslo do řetězcového sloupce způsobí uložení 123. To se ale také obvykle nedělá a do řetězcového sloupce se vždy posílají řetězce.

Ondřej Brablc:

Ono se třeba i v JavaScriptu docela často zapomíná na to, že parseInt je lepší volat s druhým parametrem 10. Pamatuji například, kdy poměrně důsledným testem složité intranetové aplikace prošla do produkce chyba, kdy nebylo možné zadat čísla 08 a 09. V testu zrovna tato dvě čísla nikdo nevyzkoušel i když test na jedno číslo s úvodní nulou byl přítomen.

Nette to ma jenom někde v laděnce a asi se to ani moc neprojeví. jQuery 1.3.2 má takový neošetřený výskyt jenom jeden a možná by se projevil při nastavování atributu "opacity".

ikona bukaJ:

Na podobný problém jsem narazil kdysi dávno při ukládání EANu do databáze. Pokud začíná na nulu (a jsou takové), tak byl problém s vsrtvou pracující nad MySQL, která EAN rozpoznala jako číslo a do SQL to vložila jako "`ean` = 0023235546", tedy bez uvozovek, což se uložilo bez nul, přestože daný sloupec je typu varchar.

optik:

Pro validaci a sanitizaci bych, pokud je to možné, používal filter extension a vyhnul se vlastním řešením. Extension je součástí php od 5.2 a obsahuje většinu běžně potřebných filtrů, float je tam také. Na nestandardní věci pak FILTER_VALIDATE_REGEXP nebo FILTER_CALLBACK

myf:

Radno by bylo ještě počítat s exponenty; '1e9' by myslím mělo být v PHP validní vyjádření kladného celého čísla, ne?

Megaloman:

Stejně jako hexadecimální a oktálová čísla :) ale to asi nespadá do původního záměru článku.

Navíc, pokud jde o kontrolu vstupních parametrů webové aplikace, tak povolení alternativ typu 1e9, 010 nebo 0x139 může vést k tomu, že uživatel sice zadá validní vstup, ale úplně jiné hodnoty, než zamýšlel.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.