regex voor float(5,2)

Hallo,

Ik heb een html-pagina waar gegevens in een database kunnen worden gezet.
1 kolom in de database is float(5,2), dus getallen met 0/1/2/3 getallen voor de punt en 0/1/2 getallen na de punt. (niet komma dus)

Nu wil ik het input veld zo maken dat het idiot-proof is.
Ik heb nu met een stukje javascript van internet zo gemaakt dat er maximaal 6 tekens kunnen worden ingevuld, en dat het alleen getallen of punten kunnen zijn.

Maar dat is niet goed genoeg. Er kunnen meer dan 3 getallen voor de punt, er kunnen meer dan 2 getallen achter de punt. Ook kan er meer dan 1 punt worden ingevuld.

Ik kan geen JS, maar heb er wel wat over gevonden.
Het blijkt dus mogelijk te zijn met regex (regular expession), maar hoe?

Ik heb er een regex gevonden die bijna doet wat ik wil: \d{1,2}[,.]\d{1,2}

Hiermee kunnen 1 of 2 getallen voor de punt staan, en 1 of 2 getallen na de punt.
Hoe zorg ik dat er 0/1/2/3 voor de punt en 0/1/2 na de punt kunnen? Klopt dit dan? \d{0-3}[.]\d{0-2}
Of moet dat anders?

Maar dat een belangrijkere vraag: hoe gebruik ik regex? Ik heb wat gevonden over het attribuut pattern, maar die blijkt niet te werken.

als ik bijvoorbeeld dit heb:


<input type="text" name="prijs" pattern="\d{1,2}[,.]\d{1,2}" />

dan is alles nog in te vullen.

Alvast bedankt!

Het pattern attribute werkt niet in Safari en niet in internet explorer eerder dan versie 10. Daarmee is het de facto onbruikbaar, tenzij je zo’n website wilt maken waar op staat “deze site werkt alleen in …”.

Je kunt overwegen het bedrag in twéé velden te splitsen. Dan hoef je met Javascript alleen maar de lengte van de invoer te beperken.

Of je controleert de invoer met javascript prijs.match(/\d{0-3}[.,]\d{0-2}/i)

Als je onkeyup gebruikt kun je na ieder teken de invoer controleren en zo nodig aanpassen.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/ time=1384611398]Het blijkt dus mogelijk te zijn met regex (regular expession), maar hoe?[/quote]Er is niet voor niets het gezegde: Ik had een probleem en probeerde dat op te lossen met een regex; toen had ik twee problemen.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/ time=1384611398]Ik heb er een regex gevonden die bijna doet wat ik wil: \d{1,2}[,.]\d{1,2}

Hiermee kunnen 1 of 2 getallen voor de punt staan, en 1 of 2 getallen na de punt.
Hoe zorg ik dat er 0/1/2/3 voor de punt en 0/1/2 na de punt kunnen? Klopt dit dan? \d{0-3}[.]\d{0-2}[/quote]

[list][]\d betekent: een getal.
[
]Accolades betekenen: “herhaal het voorgaande een bepaald aantal keer”; één getal tussen de accolades is precies zoveel keer, twee getallen is het minimum en het maximum dat je wilt vinden. Dus: \d{4} is vier getallen; \d{2,4} is twee, drie of vier getallen.
[*]Vierkante haken zet je om een reeks tekens waarvan er eentje voor moet komen: [.,] betekent dus: “een punt of een komma”; [.] zou betekenen: “een punt of … eh, tja”. De haken zijn hier dus niet nodig, omdat het je om puur en alleen een punt gaat. Je zult dan de punt trouwens ook moeten escapen, want alleen een punt betekent “een willekeurig karakter”; dat doe je met een \ ervoor.
[/list]

\d{0,3}\.\d{0,2}komt daarom denk ik beter in de buurt van wat je zoekt, maar geprobeerd heb ik het niet.

regular-expressions.info is een goede site om je eens in te verdiepen voordat je probeert aan regexen te sleutelen :slight_smile:

@domtoren
Jammer dat het niet in Safari werkt, dit zou de perfecte oplossing zijn namelijk.

@Jakko Bedankt, dit verduidelijkt het!

“prijs.match(/\d{0-3}[.,]\d{0-2}/i)”
Dat is dus om uit te voeren nadat er op verstuur is geklikt neem ik aan? Dan is het beter om het in 2 velden te splitsen.

Dat heb ik nu geprobeerd.

Ik had eerst dit in javascript:

		<script>
			function isNumberKey(evt)
			{
				var charCode = (evt.which) ? evt.which : event.keyCode
				if (charCode != 46 && charCode > 31 && (charCode < 48 || charCode > 57))
				return false;
				return true;
			}
	   </script>

Dit laat alleen getallen en punten toe. (Ik keek hier voor de character-codes, daar is 46 delete, maar dat moet wel de punt zijn. Vreemd)

En ik had dit als inputveld:

<input type='text' name='prijs' maxlength='6' onkeypress='return isNumberKey(event)' />

Wat ik nu heb gedaan is dit javascript gemaakt: (op de gok gemaakt)

	   <script>
	   	function digitsOnly(evt)
	   	{
		   	var charCode = (evt.which) ? evt.which : event.keyCode
		   	if (charCode > 31 && (charCode < 48 || charCode > 57))
		   	return false;
		   	return true;
	   	}
	   </script>

En dit als inputvelden:

<input type='text' name='prijs' maxlength='3' onkeypress='return digitsOnly(event)' size='4' />.<input type='text' name='prijsDecimaal' maxlength='2' onkeypress='return digitsOnly(event)' size='3' />

En aangezien PHP zo ongevoelig is kan ik gewoon integers gebruiken als string, en dus een punt ertussen zetten. (En dat vervolgens in de db zetten.)

Beiden bedankt voor het meedenken. Als Safari (en IE, wat niemand gebruikt) nou pattern/regex ondersteunen zou het helemaal mooi zijn!

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623300 time=1384629251]@Jakko Bedankt, dit verduidelijkt het![/quote]Mijn advies: begin eenvoudig :slight_smile:

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623300 time=1384629251]“prijs.match(/\d{0-3}[.,]\d{0-2}/i)”
Dat is dus om uit te voeren nadat er op verstuur is geklikt neem ik aan?[/quote]Je zou het ook kunnen controleren terwijl er ingetypt wordt, maar dat moet je dan wel zo implementeren dat het de gebruiker niet in de weg zit. Schakel bijvoorbeeld de “Verstuur”-knop uit zolang er geen geldige waarde in het tekstvak staat, en/of zet een icoontje bij het tekstvak dat aangeeft dat de waarde niet juist is, in plaats van allerlei toeters en bellen af te laten gaan. Doe je dat, zorg dan wel dat je óók achteraf (in de PHP die de invoer verwerkt) nog eens controleert — het is namelijk behoorlijk eenvoudig voor wie dat wil om ongeldige waardes wel degelijk te versturen. JavaScript uitschakelen zou al voldoende moeten zijn, om maar wat te noemen.

Maar: je hoeft dit niet via een regex te doen. De toegelaten mogelijkheden voor invoer zijn behoorlijk beperkt, dus je kunt het ook doen door te kijken of er een punt instaat; zo ja, te kijken hoeveel tekens er voor en achter de punt staan; en te kijken of alle tekens (behalve de punt) in de invoer getallen zijn. Dit kost meer code dan een regex, maar is waarschijnlijk eenvoudiger te schrijven als je niet enigszins vertrouwd bent met regexen.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623300 time=1384629251](Ik keek hier voor de character-codes, daar is 46 delete, maar dat moet wel de punt zijn. Vreemd)[/quote]Ik krijg de indruk dat JavaScript z’n eigen waardes voor keycodes heeft, bijvoorbeeld om te zorgen dat hoofd- en kleine letters als dezelfde gezien worden (typ op die pagina maar eens een A en een a in het tekstvak).

Oh shit, helemaal niet aan gedacht voor als je JS uit hebt staan. Heb het geprobeerd, en dan kan je gewoon weer alles invullen. helaas.

Het is een admin-pagina waar 1 persoon bij kan. Dus de kans dat hij het verkeerd doet is klein. En de kans dat z’n JS uitstaat dus ook. Maar ik wil het toch 100% idiot-proof.

Verstuur-knop uitschakelen zolang er geen geldige waarde inzit is een idee, maar ook dat is met javascript.

Het veiligst is dus om nog een extra nacontrole te doen.

PS: Heb je een voorbeeld-scriptje voor mij om de knop uit te schakelen?
Ik kan in de knop “disabled=”$disableKnop" zetten en met JS die variable TRUE of FALSE maken.

Of is wat ik nu heb + knop blokkeren + nacontrole wat overkill? :wink:

EDIT:// Ik heb preg_match() gevonden. De PHP-versie om de opbouw van een string te bekijken.
Dit wil ik als nacontrole gebruiken
Zou dit dan werken?

$pattern = '\d{0,3}\.\d{0,2}';
$prijs = $_POST['prijs'];

if( !preg_match( $pattern, $prijs ) ) {
	print("Verkeerd ingevuld");
}

Het is precies andersom, als de match er is is het goed ingevuld. En het pattern moet tussen / en /.

Als het ook een komma moet kunnen zijn moet je er van maken preg_match( ‘/\d{0,3}[.,]\d{0,2}/’, $prijs)

En ik weet niet wat je verder op in je script met $prijs doet maar het is heel onverstandig om zonder enige controle $_POST variabelen over te nemen. Dat maakt je mogelijk kwetsbaar voor SQL-injectie en dat soort ongemakken. Doe dan op zijn minst $prijs = substr($_POST[‘prijs’], 0, 6).

Serieus?

Dit is een opdracht voor school en het enige wat we hebben geleerd om SQL-injecties te voorkomen is om in de prepare() :prijs, :variabele te zetten en dat te verbinden met bindValue.

Is dat genoeg? Of zou ik dit er ook bij moeten doen?

En dan met alle veriabelen of alleen getallen?

Stond er dus. bindValue is prima.

Maar je zult de mensen de kost geven die rustig dit doen: mysql_query(“update prijzen set prijs={$prijs}”);

En als ik dan in het formulier bij het veld prijs invul “123; drop table users; drop table prijzen; drop table bestellingen” ben je mooi de l*l als ik een naam van de tabellen goed gok.

Overigens vertrouw ik nooit helemaal op bindvalue en andere in php gebouwde functies. Ik doe altijd wat extra checks, dus bijvoorbeeld in alle velden uit een formulier “drop table” vervangen door “venco” en “select” vervangen door “slect”. Baat het niet, dan schaadt het niet.

Hah dat is best slim.

Overigens is dit de admin-side, dus er kan 1 persoon bij (of meerdere die ook eigenaar zijn)

Omdat ze geen computer experts zijn wilde ik zorgen dat ze geen foute input kunnen geven, maar sql injecties kunnen ze niet. :wink:

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623483 time=1384685312]helemaal niet aan gedacht voor als je JS uit hebt staan. Heb het geprobeerd, en dan kan je gewoon weer alles invullen. helaas.[/quote]Ja, dat bedoelde ik dus :slight_smile:

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623483 time=1384685312]Het is een admin-pagina waar 1 persoon bij kan. Dus de kans dat hij het verkeerd doet is klein. En de kans dat z’n JS uitstaat dus ook. Maar ik wil het toch 100% idiot-proof.[/quote]Je moet het zo zien: de controle in JavaScript is voor het gemak van de gebruiker, die in PHP is de échte. Verder helpt het ook om verkeer naar de webserver te verkleinen, omdat die minder vaak pagina’s met ongeldige invoer zal hoeven te verwerken om dan een foutmelding en de vraag om beter moet serveren.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623483 time=1384685312]Verstuur-knop uitschakelen zolang er geen geldige waarde inzit is een idee, maar ook dat is met javascript.[/quote]Dat is toch geen probleem? Heeft de gebruiker JavaScript aanstaan dan werkt het, staat dat uit dan heeft hij of zij er geen weet en dus ook geen last van.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623483 time=1384685312]Ik kan in de knop “disabled=”$disableKnop" zetten en met JS die variable TRUE of FALSE maken.[/quote]Je hoeft in de knop niks te zetten, maar in de JavaScript kun je inderdaad de disabled van de knop aan- of uitzetten. Als je die controle uitvoert bij elke toetsaanslag werkt het “live”.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623483 time=1384685312]Of is wat ik nu heb + knop blokkeren + nacontrole wat overkill? ;)[/quote]Nee :slight_smile:

Dat het ‘live’ werkt vind ik nog steeds erg fijn! :slight_smile:

Mijn heb nog een vraagje (beetje off-topic misschien): Wat is het tegenovergestelde van NULL?

Ik heb namelijk een if-statement met een aantal van zulke vergelijkingen erin: !$_SESSION[‘naamLeeg’]

Maar als ik een perfecte gebruiker heb wordt die nooit TRUE gemaakt, dus dan is die NULL:

if(empty($naam)) {
	$_SESSION['naamLeeg'] = TRUE;
}

Als !NULL == TRUE, dan is er geen probleem. Anders moet ik alles eerst FALSE maken.

Ik doe meestal if ( trim($naam) == “” ) enz.

De trim haalt spaties e.d. van begin en eind.

Het controleren van invoer vraagt zorgvuldigheid. Ik erger me enorm aan website waar je de postcode in moet vullen als 1234AB en 1234 AB (met spatie) niet goed is. Of andersom. Denk dan even met je klant mee, reken beiden goed en zet dan in je PHP de postcode in het format dat je hebben wilt. Iets meer werk voor de programmeur, veel fijner voor de klant.

[quote=Domtoren url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623946 time=1384761864]Ik erger me enorm aan website waar je de postcode in moet vullen als 1234AB en 1234 AB (met spatie) niet goed is.[/quote]Aha, ik ben niet de enige :slight_smile: Nog erger is als ze dan ook nog size=“6” aan het tekstvak meegegeven hebben. Zo moeilijk is het allemaaerschillende mogelijkheden allemaal goed te rekenen … haal gewoon alle spaties eruit en controleer dan pas of het wel een postcode lijkt te zijn, bijvoorbeeld.

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623829 time=1384720970]Wat is het tegenovergestelde van NULL?[/quote]Eh … alles? Zodra iets een waarde heeft is het niet NULL, zou ik denken (maar ik heb me er niet in verdiept wat PHP’s definitie precies is).

[quote=Dr. User url=http://www.onemorething.nl/community/topic/regex-voor-float52/#post-2623829 time=1384720970]Als !NULL == TRUE, dan is er geen probleem. Anders moet ik alles eerst FALSE maken.[/quote]Als je null != $welkeanderewaardedanook doet, levert dat 1 op, dus null is niet gelijk aan true.