[PHP/regexp] Characters met diacritics valideren*

Pagina: 1
Acties:

Onderwerpen


  • amarok
  • Registratie: Januari 2009
  • Laatst online: 09-09 12:15
Voor een webshop ben ik in PHP een script aan het schrijven dat d.m.v. regular expressions checkt of de input van de koper aan bepaalde voorwaarden voldoet. Klant moet bijv. het land invullen waar de bestelling naar toe verstuurd moet worden. Ik heb nu deze regexp:

/^[a-zA-Z\- ]+$/

Als de gebruiker nu België invoert (dus een 'e' met een trema) wordt de input afgekeurd. Is het nu de bedoeling dat aan de regular expression ALLE letters met leestekens toegevoegd worden of kan het handiger? Heeft dit iets met Unicode te maken?

  • sub0kelvin
  • Registratie: September 2002
  • Laatst online: 10-08-2023
[a-z] bevat inderdaad geen speciale letters. Je zou kunnen kijken naar http://nl3.php.net/manual/en/regexp.reference.backslash.php en dan met name \w. Die is namelijk locale-afhankelijk.

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 17-09 18:39

Matis

Rubber Rocket

Ik gebruik dit om ongure karakters te verwijderen uit een string
PHP:
1
$location = preg_replace('/[^(\x20-\x7F)]*/','', $location);


Wat hij doet, hij checkt de ascii-waardes van de karakters, vallen die buiten de range, dan vervangt hij hem door niets.
Als jij zoiets doet met een preg_match en de ascii-waardes goed zet, dan kun je daarop controleren en evt. actie ondernemen!

Voorbeeldje van php.net
PHP:
1
2
// remove all non-ASCii characters
$s    = preg_replace( '@[^\0-\x80]@u'    , "",    $s );

[ Voor 15% gewijzigd door Matis op 23-09-2009 12:56 . Reden: tags FTW :D ]

If money talks then I'm a mime
If time is money then I'm out of time


  • HuHu
  • Registratie: Maart 2005
  • Niet online
Tip: laat de klant het land niet invullen, maar laat hem kiezen uit een lange lijst en sla de ISO 3166-1 code op. Bij voorkeur de alpha-2.

  • amarok
  • Registratie: Januari 2009
  • Laatst online: 09-09 12:15
sub0kelvin schreef op woensdag 23 september 2009 @ 12:49:
[a-z] bevat inderdaad geen speciale letters. Je zou kunnen kijken naar http://nl3.php.net/manual/en/regexp.reference.backslash.php en dan met name \w. Die is namelijk locale-afhankelijk.
Ik denk dat dit inderdaad de oplossing is. Dank! :) Heb het uitgeprobeerd op http://rubular.com en daar werkt het goed.

Het probleem wat ik nu nog met het script heb is dat zodra ik 'belgië' invoer en hij het valideert, de input afgekeurd wordt. Het script herlaadt dan de pagina en vult de door de user ingevoerde input weer in de velden in. De input van het veld 'Land' is dan verminkt; er staat: 'belgië'.

Zodra ik in Chrome Codering op ISO-8859-15 zet, dan blijft de input na het valideren wel intact. Maar het wordt nog wel afgekeurd door het script.
Het zal wel iets met verschillende charsets te maken hebben. Het is de bedoeling om utf-8 te gebruiken, maar wellicht dat de browser, Apache, en/of PHP niet de juiste set gebruiken. Weet niet zo goed waar ik moet beginnen met uitzoeken...

Bij het gebruik maken van $_POST en $_SESSION, moet je dan ook rekeninghouden met charsets? Is er misschien op Internet ergens een goed document om te lezen over charsets, locale's en wat nog meer zij??

Iedereen in ieder geval bedankt voor de antwoorden tot nu toe.

P.S.: Wat betreft de ISO 3361-1 lijst, daar heb ik ook wel aan gedacht, maar kon toen niet een goede Nederlandstalige lijst vinden die (eenvoudig) in een drop-down box gegoten kon worden. Wellicht dat ik dit nog wel ga toepassen...

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Kijk voor die dropdown eens naar Zend_Locale, onderdeel van het Zend Framework. Daar kun je zo een lijst uit trekken, beschikbaar in alle talen van de wereld.

  • amarok
  • Registratie: Januari 2009
  • Laatst online: 09-09 12:15
HuHu schreef op woensdag 23 september 2009 @ 16:13:
Kijk voor die dropdown eens naar Zend_Locale, onderdeel van het Zend Framework. Daar kun je zo een lijst uit trekken, beschikbaar in alle talen van de wereld.
Ah, ik heb wel van Zend gehoord, maar nog niet eerder gebruikt. Dit is wel interessant om naar te kijken. Dank! :)


Ben ondertussen iets verder met het probleem. Gebruik nu overal utf-8 en de input wordt niet vernaggeld. Ik gebruikte in een functie htmlentities() en dat leverde een &euml op, waardoor de regexp struikelde over de ampersand. In de functie is deze nu vervangen door htmlspecialchars().

Nog steeds wordt de string 'belgië' afgekeurd door PHP. Ik heb een testscriptje geschreven dat er zo uitziet:
PHP:
1
2
3
4
5
<?php
  $regexp="/^[\w]+$/";
  $string="belgie";
  echo(preg_match($regexp, $string));
?>


De output van dit script is: '1', de string matched dus met de regexp. Echter, vervang ik 'belgie' door 'belgië', dan krijg ik output: '0'. Valt in PHP (5.1) de letter 'ë' niet onder \w in een regexp? Heb het getest op de site http://rubular.com en daar werkt het wel... :?

  • Duroth
  • Registratie: Juni 2007
  • Laatst online: 27-04-2016

Duroth

No rest for the tweaked

sub0kelvin schreef op woensdag 23 september 2009 @ 12:49:
[a-z] bevat inderdaad geen speciale letters. Je zou kunnen kijken naar http://nl3.php.net/manual/en/regexp.reference.backslash.php en dan met name \w. Die is namelijk locale-afhankelijk.
@TS: Wellicht heb je de verkeerde locale ingesteld staan in PHP?

Acties:
  • 0 Henk 'm!

  • DexterDee
  • Registratie: November 2004
  • Nu online

DexterDee

I doubt, therefore I might be

PHP5 heeft geen goede support voor multibyte karakters. Dat komt pas in PHP6. Om deze reden moet je de reguliere preg* en ereg* functies niet gebruiken voor het matchen van diakritische karakters.

Een betere optie (en ook door mijzelf werkend getest) is gebruik maken van de MBString extensie van PHP. Hierin zitten namelijk ook regular expression functies.

Hier even uit het hoofd een voorbeeldje ingetikt:

PHP:
1
2
3
4
5
6
mb_regex_encoding("UTF-8");
if(mb_ereg(".*([a-zéëèáäàúüùíïìóöò]).*", $input)) {
    echo "Tweakers!";
} else {
    echo "Nope...";
}


Je kunt hiermee ook ranges aangeven, maar die zitten helaas niet allemaal mooi bijelkaar. De range [À-Å] bevat deze karakters: À, Á, Â, Ã, Ä, Å

Ik heb niet getest of de \w parameter werkt. Dat hangt ook heel erg af van je locale. een ķ zul je bijvoorbeeld alleen in het turks tegenkomen en een andere locale ziet dat dus als een niet geldig teken. Landsnamen kunnen diakritische tekens bevatten van meerdere locales. Zo is er bijvoorbeeld een scandinavisch staatje die begint met de letter Å. Als je de locale dan vast zet kom je in de problemen.

Ik kan me trouwens ook voorstellen dat je deze validatie nog op andere velden wilt gebruiken, bijvoorbeeld de stadsnaam. Dan ga je natuurlijk nog meer varianten tegenkomen en helpt het niet meer om uit een voorgedefinieerd lijstje te kiezen.

[ Voor 41% gewijzigd door DexterDee op 25-09-2009 12:59 ]

Klik hier om mij een DM te sturen • 3245 WP op ZW


Acties:
  • 0 Henk 'm!

  • Ram0n
  • Registratie: Maart 2002
  • Laatst online: 03-07 13:05

Ram0n

Bierbrouwende nerd

Niet de meest nette methode, maar wellicht wel eentje die je kan gebruiken om het voor nu te fixen:

PHP:
1
2
3
4
5
6
7
8
9
10
11
$tabel = array(
      'Ŝ'=>'S', 'š'=>'s', '&#272;'=>'Dj', '&#273;'=>'dj', 'Ž'=>'Z', 'ž'=>'z', '&#268;'=>'C', '&#269;'=>'c', '&#262;'=>'C', '&#263;'=>'c',
      'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
      'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
      'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss',
      'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e',
      'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o',
      'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b',
      'ÿ'=>'y', '&#340;'=>'R', '&#341;'=>'r', '$'=>'s'
  );
  $string2 = strtr($string, $table);


Dit vervangt een aantal "rare" tekens in $string naar $string2, vervolgens kan je de simpele \w regex uitvoeren op $string2 en kijken of hij dan geldig is.

Eigenaar/brouwer Milky Road Brewery


Acties:
  • 0 Henk 'm!

  • amarok
  • Registratie: Januari 2009
  • Laatst online: 09-09 12:15
Ik heb het voorlopig zo opgelost:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
  $string="België";
  $strlen=mb_strlen($string);
  $regexp="[a-zéëèáäàúüùíïìóöò]{". $strlen . "}";
  echo $regexp . "<br>\n";
  echo $string . "<br>\n";
  echo $strlen . "<br>\n";
  if($returncode = mb_eregi($regexp, $string))
  {
    echo "Matched!<br>";
  } else
  {
    echo "Not matched!<br>";
  }
  echo $returncode;
?>


Ik heb de stringlengte aan de regexp toegevoegd, omdat de hele string moet matchen. Laat je die weg of zet je er .* voor en achter, dan matched de string al bij één correct teken.

Iedereen erg bedankt voor zijn antwoorden! _/-\o_

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
amarok schreef op maandag 28 september 2009 @ 11:54:
Ik heb de stringlengte aan de regexp toegevoegd, omdat de hele string moet matchen. Laat je die weg of zet je er .* voor en achter, dan matched de string al bij één correct teken.
Euh; als je dan toch per-se regex wil gebruiken, verdiep je dan even in hoe die dingen precies werken. Dit is nou niet bepaald de manier ;) (Hoewel creatief gevonden :P )

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Heel mooi gevonden inderdaad. :D

En toch doet ^[a-zéëèáäàúüùíïìóöò]+$ exact hetzelfde. Of een * in plaats van een + als de string ook leeg mag zijn. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
geweldig ja :+

Overigens kan ik me erg vinden in HuHu zn snel gegeven antwoord, dat neemt je problemen meteen allemaal weg.

Acties:
  • 0 Henk 'm!

  • amarok
  • Registratie: Januari 2009
  • Laatst online: 09-09 12:15
Hehe, ik heb inderdaad snel door een Posix Extended Regular Expressions tutorial heengelezen en dat met die $ niet gezien. 8)

Ik pas het aan...
Pagina: 1