Sie sind auf Seite 1von 21


(PHP 4, PHP 5) preg_match Perform a regular expression match

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] ) Searches subject for a match to the regular expression given in pattern.


The pattern to search for, as a string.


The input string.


If matches is provided, then it is filled with the results of search. $matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.
flags flags

can be the following flag:


If this flag is passed, for every occurring match the appendant string offset will also be returned. Note that this changes the value of matches into an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.

Normally, the search starts from the beginning of the subject string. The optional parameter offset can be used to specify the alternate place from which to start the search (in bytes). Note: Using offset is not equivalent to passing substr($subject, $offset) to preg_match() in place of the subject string, because pattern can contain assertions such as ^, $ or (?<=x). Compare:
<?php $subject = "abcdef"; $pattern = '/^def/'; preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3); print_r($matches); ?>

The above example will output:

Array ( )

while this example

<?php $subject = "abcdef"; $pattern = '/^def/'; preg_match($pattern, substr($subject,3), $matches, PREG_OFFSET_CAPTURE); print_r($matches); ?>

will produce
Array ( [0] => Array ( [0] => def [1] => 0 ) )

Return Values
preg_match() returns the number of times pattern matches. That will be either 0 times (no match) or 1 time because preg_match() will stop searching after the first match. preg_match_all() on the contrary will continue until it reaches the end of subject. preg_match() returns FALSE if an error occurred. Report a bug

Version Description 5.3.6 Returns FALSE if offset is higher than subject length. Named subpatterns now accept the syntax (?<name>) and (?'name') as well as (?P<name>). Previous 5.2.2 versions accepted only (?P<name>). 4.3.3 The offset parameter was added 4.3.0 The PREG_OFFSET_CAPTURE flag was added 4.3.0 The flags parameter was added Report a bug

Example #1 Find the string of text "php"
<?php // The "i" after the pattern delimiter indicates a case-insensitive search if (preg_match("/php/i", "PHP is the web scripting language of choice.")) { echo "A match was found."; } else { echo "A match was not found."; } ?>

Example #2 Find the word "web"

<?php /* The \b in the pattern indicates a word boundary, so only the distinct * word "web" is matched, and not a word partial like "webbing" or "cobweb" */ if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice.")) { echo "A match was found."; } else { echo "A match was not found."; } if (preg_match("/\bweb\b/i", "PHP is the website scripting language of choice.")) { echo "A match was found."; } else { echo "A match was not found."; } ?>

Example #3 Getting the domain name out of a URL

<?php // get host name from URL preg_match('@^(?:http://)?([^/]+)@i', "", $matches); $host = $matches[1]; // get last two segments of host name preg_match('/[^.]+\.[^.]+$/', $host, $matches); echo "domain name is: {$matches[0]}\n"; ?>

The above example will output:

domain name is:

Example #4 Using named subpattern

<?php $str = 'foobar: 2008'; preg_match('/(?P<name>\w+): (?P<digit>\d+)/', $str, $matches); /* This also works in PHP 5.2.2 (PCRE 7.0) and later, however * the above form is recommended for backwards compatibility */ // preg_match('/(?<name>\w+): (?<digit>\d+)/', $str, $matches); print_r($matches); ?>

The above example will output:

Array ( [0] => foobar: 2008 [name] => foobar [1] => foobar [digit] => 2008 [2] => 2008 )

Report a bug

Tip Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster. Report a bug

See Also

PCRE Patterns preg_match_all() - Perform a global regular expression match preg_replace() - Perform a regular expression search and replace preg_split() - Split string by a regular expression preg_last_error() - Returns the error code of the last PCRE regex execution



[edit] Last updated: Fri, 30 Sep 2011

add a note User Contributed Notes preg_match force at md-t dot org 26-Sep-2011 06:38 Simple regex Regex quick reference [abc] A single character: a, b or c [^abc] Any single character but a, b, or c [a-z] Any single character in the range a-z [a-zA-Z] Any single character in the range a-z or A-Z ^ Start of line $ End of line \A Start of string \z End of string . Any single character \s Any whitespace character \S Any non-whitespace character \d Any digit \D Any non-digit \w Any word character (letter, number, underscore) \W Any non-word character \b Any word boundary character (...) Capture everything enclosed (a|b) a or b a? Zero or one of a a* Zero or more of a a+ One or more of a a{3} Exactly 3 of a a{3,} 3 or more of a a{3,6} Between 3 and 6 of a options: i case insensitive m make dot match newlines x ignore whitespace in regex o perform #{...} substitutions only once

cmallabon at homesfactory dot com 31-Aug-2011 05:28

Just an interesting note. Was just updating code to replace ereg() with strpos() and preg_match and the thought occured that preg_match() could be optimized to quit early when

only searching if a string begins with something, for example <?php if(preg_match("/^http/", $url)) { //do something } ?> vs <?php if(strpos($url, "http") === 0) { //do something } ?> As I guessed, strpos() is always faster (about 2x) for short strings like a URL but for very long strings of several paragraphs (e.g. a block of XML) when the string doesn't start with the needle preg_match as twice as fast as strpos() as it doesn't scan the entire string. So, if you are searching long strings and expect it to normally be true (e.g. validating XML), strpos() is a much faster BUT if you expect if to often fail, preg_match is the better choice.

ayman2243 at gmail dot com 30-Aug-2011 11:55

highlight Search Words <?php function highlight($word, $subject) { $split_subject = explode(" ", $subject); $split_word = explode(" ", $word); foreach ($split_subject as $k => $v){ foreach ($split_word as $k2 => $v2){ if($v2 == $v){ $split_subject[$k] = "<span class='highlight'>".$v."</span>"; } } } return implode(' ', $split_subject); } ?>

Khalid_Moharram at hotmail dot com 25-Aug-2011 08:36

Well for anyone looking for email validation, according to the RFC specifications (ONLY FOR ((ENGLISH ASCII)) E-Mails). <?php function email_valid($temp_email) { ######## Three functions to HELP ######## function valid_dot_pos($email) { $str_len = strlen($email); for($i=0; $i<$str_len; $i++) { $current_element = $email[$i]; if($current_element == "." && ($email[$i+1] == ".")) { return false; break; } else { } } return true;

} function valid_local_part($local_part) { if(preg_match("/[^a-zA-Z0-9-_@.!#$%&'*\/+=?^`{\|}~]/", $local_part)) { return false; } else { return true; } } function valid_domain_part($domain_part) { if(preg_match("/[^a-zA-Z0-9@#\[\].]/", $domain_part)) { return false; } elseif(preg_match("/[@]/", $domain_part) && preg_match("/[#]/", $domain_part)) { return false; } elseif(preg_match("/[\[]/", $domain_part) || preg_match("/[\]]/", $domain_part)) { $dot_pos = strrpos($domain_part, "."); if(($dot_pos < strrpos($domain_part, "]")) || (strrpos($domain_part, "]") < strrpos($domain_part, "["))) { return true; } elseif(preg_match("/[^0-9.]/", $domain_part)) { return false; } else { return false; } } else { return true; } } // trim() the entered E-Mail $str_trimmed = trim($temp_email); // find the @ position $at_pos = strrpos($str_trimmed, "@"); // find the . position $dot_pos = strrpos($str_trimmed, "."); // this will cut the local part and return it in $local_part $local_part = substr($str_trimmed, 0, $at_pos); // this will cut the domain part and return it in $domain_part $domain_part = substr($str_trimmed, $at_pos); if(!isset($str_trimmed) || is_null($str_trimmed) || empty($str_trimmed) || $str_trimmed == "") { $this->email_status = "You must insert something"; return false; } elseif(!valid_local_part($local_part)) { $this->email_status = "Invalid E-Mail Address"; return false; } elseif(!valid_domain_part($domain_part)) { $this->email_status = "Invalid E-Mail Address"; return false; } elseif($at_pos > $dot_pos) { $this->email_status = "Invalid E-Mail Address"; return false; } elseif(!valid_local_part($local_part)) { $this->email_status = "Invalid E-Mail Address"; return false; } elseif(($str_trimmed[$at_pos + 1]) == ".") { $this->email_status = "Invalid E-Mail Address";

return false; } elseif(!preg_match("/[(@)]/", $str_trimmed) || !preg_match("/[(.)]/", $str_trimmed)) { $this->email_status = "Invalid E-Mail Address"; return false; } else { $this->email_status = ""; return true; } } ?>

workhorse at op dot pl 11-Aug-2011 07:53

Preg_match returns empty result trying to validate $subject with carriege returns (/n/r). To solve it one need to use /s modifier in $pattern string. <?php $pattern='/.*/s'; $valid=preg_match($pattern, $subject, $match); ?>

itworkarounds at gmail dot com 09-Aug-2011 04:08

You can use the following code to detect non-latin (Cyrilic, Arabic, Greek...) characters: <?php preg_match("/^[a-zA-Z\p{Cyrillic}0-9\s\-]+$/u", "ABC abc 1234 "); ?>

mohammad40g at gmail dot com 02-Aug-2011 04:23

This sample is for checking persian character: <?php preg_match("/[\x{0600}-\x{06FF}\x]{1,32}/u", ';)' ?>

sun at drupal dot org 24-Jun-2011 12:56

Basic test for invalid UTF-8 that can hi-jack IE: <?php $valid = (preg_match('/^./us', $text) == 1); ?> See for details. --Test for valid UTF-8 and XML/XHTML character range compatibility: <?php $invalid = preg_match('@[^\x9\xA\xD\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]@u', $text) ?> Ref:

juanmadss at gmail dot com 25-May-2011 11:00

Testing the speed of preg_match against stripos doing insensitive case search in strings: <?php $string = "Hey, how are you? I'm a string."; // PCRE $start = microtime(true); for ($i = 1; $i < 10000000; $i++) { $bool = preg_match('/you/i', $string); } $end = microtime(true); $pcre_lasted = $end - $start; // 8.3078360557556 // Stripos, we believe in you $start = microtime(true);

for ($i = 1; $i < 10000000; $i++) { $bool = stripos($string, 'you') !== false; } $end = microtime(true); $stripos_lasted = $end - $start; // 6.0306038856506 echo "Preg_match lasted: {$pcre_lasted}<br />Stripos lasted: {$stripos_lasted}"; ?> So unless you really need to test a string against a regular expression, always use strpos / stripos and other string functions to find characters and strings within other strings.

mulllhausen 16-May-2011 08:57

i do a fair bit of html scraping in conjunction with curl. i always need to know if i have reached the right page or if the curl request failed. the main problem i have encountered is html tags having unexpected spaces or other characters (especially the &nbsp; character sequence) between them. for example when requesting a page with a certain manner set of post or get variables the response might be <a href='blah'><span>data data data</span></a> but requesting the same page with different post/get variables might give the following result: <a href='blah'> &nbsp;<span>data data data</span> </a> to match both of these tag sequences with the same pattern i use the [\S\s]*? wildcard which basically means 'match anything at all...but not if you can help it' so the pattern for the above sequence would be: <?php $page1 = "........<a href='blah'><span>data data data</span></a>........."; $page2 = "........<a href='blah'> &nbsp;<span>data data data</span> </a> ........"; $w = "[\s\S]*?"; //ungreedy wildcard $pattern = "/\<a href='blah'\>$w\<span\>data data data\<\/span\>$w\<\/a\>/"; if(preg_match($pattern, $page1, $matches)) echo "got to page 1. match: [".print_r($matches, true)."]\n"; else echo "did not get to page 1\n"; if(preg_match($pattern, $page2, $matches)) echo "got to page 2. match: [".print_r($matches, true)."]\n"; else echo "did not get to page 2\n"; ?>

MrBull 20-Mar-2011 03:32

Sometimes its useful to negate a string. The first method which comes to mind to do this is: [^(string)] but this of course won't work. There is a solution, but it is not very well known. This is the simple piece of code on how a negation of a string is done: (?:(?!string).) ?: makes a subpattern (see and ?! is a negative look ahead. You put the negative look ahead in front of the dot because you want the regex engine to first check if there is an occurrence of the string you are negating. Only if it is not there, you want to match an arbitrary character.

Hope this helps some ppl.

arash dot hemmat at gmail dot com 03-Feb-2011 03:15

For those who search for a unicode regular expression example using preg_match here it is: Check for Persian digits preg_match( "/[^\x{06F0}-\x{06F9}\x]+/u" , '' );

Frank 26-Jan-2011 08:12

If someone is from a country that accepts decimal numbers in format 9.00 and 9,00 (point or comma), number validation would be like that: <?php $number_check = "9,99"; if (preg_match( '/^[\-+]?[0-9]*\.*\,?[0-9]+$/', $number_check)) { return TRUE; } ?> However, if the number will be written in the database, most probably this comma needs to be replaced with a dot. This can be done with use of str_replace, i.e : <?php $number_database = str_replace("," , "." , $number_check); ?>

sainnr at gmail dot com 30-Dec-2010 02:12

This sample regexp may be useful if you are working with DB field types. (?P<type>\w+)($|\((?P<length>(\d+|(.*)))\)) For example, if you are have a such type as "varchar(255)" or "text", the next fragment <?php $type = 'varchar(255)'; // type of field preg_match('/(?P<type>\w+)($|\((?P<length>(\d+|(.*)))\))/', $type, $field); print_r($field); ?> will output something like this: Array ( [0] => varchar(255) [type] => varchar [1] => varchar [2] => (255) [length] => 255 [3] => 255 [4] => 255 )

ian_channing at hotmail dot com 27-Dec-2010 09:55

When trying to check a file path that could be windows or unix it took me quite a few tries to get the escape characters right. The Unix directory separator must be escaped once and the windows directory separator must be escaped twice. This will match path/to/file and path\to\file.exe preg_match('/^[a-z0-9_.\/\\\]*$/i', $file_string);

SoN9ne at gmail dot com 08-Jun-2010 05:10

I have been working on a email system that will automatically generate a text email from a given HTML email by using strip_tags(). The only issue I ran into, for my needs, were that the anchors would not keep their links. I search for a little while and could not find anything to strip the links from the tags so I generated my own little snippet. I am posting it here in hopes that others may find it useful and for later reference. A note to keep in mind: I was primarily concerned with valid HTML so if attributes do no use ' or " to contain the values then this will need to be tweaked. If you can edit this to work better, please let me know. <?php /** * Replaces anchor tags with text * - Will search string and replace all anchor tags with text (case insensitive)

* * How it works: * - Searches string for an anchor tag, checks to make sure it matches the criteria * Anchor search criteria: * - 1 - <a (must have the start of the anchor tag ) * - 2 - Can have any number of spaces or other attributes before and after the href attribute * - 3 - Must close the anchor tag * * - Once the check has passed it will then replace the anchor tag with the string replacement * - The string replacement can be customized * * Know issue: * - This will not work for anchors that do not use a ' or " to contain the attributes. * (i.e.- <a href=http: //></a> will not be replaced) */ function replaceAnchorsWithText($data) { /** * Had to modify $regex so it could post to the site... so I broke it into 6 parts. */ $regex = '/(<a\s*'; // Start of anchor tag $regex .= '(.*?)\s*'; // Any attributes or spaces that may or may not exist $regex .= 'href=[\'"]+?\s*(?P<link>\S+)\s*[\'"]+?'; // Grab the link $regex .= '\s*(.*?)\s*>\s*'; // Any attributes or spaces that may or may not exist before closing tag $regex .= '(?P<name>\S+)'; // Grab the name $regex .= '\s*<\/a>)/i'; // Any number of spaces between the closing anchor tag (case insensitive) if (is_array($data)) { // This is what will replace the link (modify to you liking) $data = "{$data['name']}({$data['link']})"; } return preg_replace_callback($regex, 'replaceAnchorsWithText', $data); } $input = 'Test 1: <a href="http: //php.net1">PHP.NET1</a>.<br />'; $input .= 'Test 2: <A name="test" HREF=\'HTTP: //PHP.NET2\' target="_blank">PHP.NET2</A>.<BR />'; $input .= 'Test 3: <a hRef=http: //php.net3>php.net3</a><br />'; $input .= 'This last line had nothing to do with any of this'; echo ?> Will Test Test Test This replaceAnchorsWithText($input).'<hr/>'; output: 1: PHP.NET1(http: //php.net1). 2: PHP.NET2(HTTP: //PHP.NET2). 3: php.net3 (is still an anchor) last line had nothing to do with any of this

Posting to this site is painful... Had to break up the regex and had to break the test links since it was being flagged as spam...

teracci2002 09-Apr-2010 04:00

When you use preg_match() for security purpose or huge data processing, mayby you should make consideration for backtrack_limit and recursion_limit. These limits may bring wrong matching result. You can verify whether you hit these limits by checking preg_last_error().

Kae Cyphet 18-Mar-2010 02:29

for those coming over from ereg, preg_match can be quite intimidating. to get started here is a migration tip.

<?php if(ereg('[^0-9A-Za-z]',$test_string)) // will be true if characters arnt 0-9, A-Z or a-z. if(preg_match('/[^0-9A-Za-z]/',$test_string)) // this is the preg_match version. the /'s are now required. ?>

plasma 22-Feb-2010 12:53

To extract scheme, host, path, ect. simply use <?php $url = 'http://name:pass@'; $url .= ''; $url .= '/path/to/file.php?a=1&amp;b=2#anchor'; $url_data = parse_url ( $url ); print_r ( $url_data ); ?> ___ prints out something like: Array ( [scheme] => http [host] => [port] => 10000 [user] => name [pass] => pass [path] => /path/to/file.php [query] => a=1&b=2 [fragment] => anchor ) In my tests parse_url is up to 15x faster than preg_match(_all)!

Dr@ke 18-Feb-2010 03:58

Hello, There is a bug with somes new PCRE versions (like:7.9 2009-04-1), In patterns: \w+ !== [a-zA-Z0-9]+ But it's ok, if i replace \w+ by [a-z0-9]+ or [a-zA-Z0-9]+

saberdream at live dot fr 10-Feb-2010 11:53

I made a function to circumvent the problem of length of a string... This verifies that the link is an image. <?php function verifiesimage($lien, $limite) { if( preg_match('#^http:\/\/(.*)\.(gif|png|jpg)$#i', $lien) && strlen($lien) < $limite ) { $msg = TRUE; // link ok } else { $msg = FALSE; // the link isn't image } return $msg; // return TRUE or FALSE } ?> Example : <?php if(verifierimage($votrelien, 50) == TRUE)

{ // we display the content... } ?>

Anonymous 06-Feb-2010 04:00

The regular expression for breaking-down a URI reference into its components: ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9 Source:

cebelab at gmail dot com 24-Jan-2010 06:43

I noticed that in order to deal with UTF-8 texts, without having to recompile php with the PCRE UTF-8 flag enabled, you can just add the following sequence at the start of your pattern: (*UTF8) for instance : '#(*UTF8)[[:alnum:]]#' will return TRUE for '' where '#[[:alnum:]]#' will return FALSE found this very very useful tip after hours of research over the web directly in pcre website right here : there are many further informations about UTF-8 support in the lib hop that will help! -cedric

Stefan 17-Nov-2009 10:47

I spent a while replacing all my ereg() calls to preg_match(), since ereg() is now deprecated and will not be supported as of v 6.0. Just a warning regarding the conversion, the two functions behave very similarly, but not exactly alike. Obviously, you will need to delimit your pattern with '/' or '|' characters. The difference that stumped me was that preg_replace overwrites the $matches array regardless if a match was found. If no match was found, $matches is simply empty. ereg(), however, would leave $matches alone if a match was not found. In my code, I had repeated calls to ereg, and was populating $matches with each match. I was only interested in the last match. However, with preg_match, if the very last call to the function did not result in a match, the $matches array would be overwritten with a blank value. Here is an example code snippet to illustrate: <?php $test = array('yes','no','yes','no','yes','no'); foreach ($test as $key=>$value) { ereg("yes",$value,$matches1); preg_match("|yes|",$value,$matches2); } print "ereg result: $matches1[0]<br>"; print "preg_match result: $matches2[0]<br>"; ?> The output is: ereg result: yes preg_match result: ($matches2[0] in this case is empty) I believe the preg_match behavior is cleaner. I just thought I would report this to hopefully save others some time.

ruakuu at NOSPAM dot com 04-Nov-2009 05:32

Was working on a site that needed japanese and alphabetic letters and needed to validate input using preg_match, I tried using \p{script} but didn't work: <?php $pattern ='/^([-a-zA-Z0-9_\p{Katakana}\p{Hiragana}\p{Han}]*)$/u'; // Didn't work ?> So I tried with ranges and it worked: <?php $pattern ='/^[-a-zA-Z0-9_\x{30A0}-\x{30FF}' .'\x{3040}-\x{309F}\x{4E00}-\x{9FBF}\s]*$/u'; $match_string = ' '; if (preg_match($pattern, $match_string)) { echo "Found - pattern $pattern"; } else { echo "Not found - pattern $pattern"; } ?> U+4E00U+9FBF Kanji U+3040U+309F Hiragana U+30A0U+30FF Katakana Hope its useful, it took me several hours to figure it out.

Anonymous 12-Oct-2009 09:24

If your regular expression does not match with long input text when you think it should, you might have hit the PCRE backtrack default limit of 100000. See

splattermania at freenet dot de 01-Oct-2009 12:01

As I wasted lots of time finding a REAL regex for URLs and resulted in building it on my own, I now have found one, that seems to work for all kinds of urls: <?php $regex $regex $regex $regex $regex $regex $regex ?> = "((https?|ftp)\:\/\/)?"; // SCHEME .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; // User and Pass .= "([a-z0-9-.]*)\.([a-z]{2,3})"; // Host or IP .= "(\:[0-9]{2,5})?"; // Port .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; // Path .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?"; // GET Query .= "(#[a-z_.-][a-z0-9+\$_.-]*)?"; // Anchor

Then, the correct way to check against the regex ist as follows: <?php if(preg_match("/^$regex$/", $url)) { return true; } ?>

luc _ santeramo at t yahoo dot com 03-Sep-2009 02:46

If you want to validate an email in one line, use filter_var() function ! easy use, as described in the document example : var_dump(filter_var('', FILTER_VALIDATE_EMAIL));

marcosc at tekar dot net 27-Aug-2009 04:31

When using accented characters and "" (), preg_match does not work. It is a charset problem, use utf8_decode/decode to fix.

ian_channing at hotmail dot com 20-Aug-2009 01:13

This is a function that uses regular expressions to match against the various VAT formats required across the EU.

<?php /** * @param integer $country Country name * @param integer $vat_number VAT number to test e.g. GB123 4567 89 * @return integer -1 if country not included OR 1 if the VAT Num matches for the country OR 0 if no match */ function checkVatNumber( $country, $vat_number ) { switch($country) { case 'Austria': $regex = '/^(AT){0,1}U[0-9]{8}$/i'; break; case 'Belgium': $regex = '/^(BE){0,1}[0]{0,1}[0-9]{9}$/i'; break; case 'Bulgaria': $regex = '/^(BG){0,1}[0-9]{9,10}$/i'; break; case 'Cyprus': $regex = '/^(CY){0,1}[0-9]{8}[A-Z]$/i'; break; case 'Czech Republic': $regex = '/^(CZ){0,1}[0-9]{8,10}$/i'; break; case 'Denmark': $regex = '/^(DK){0,1}([0-9]{2}[\ ]{0,1}){3}[0-9]{2}$/i'; break; case 'Estonia': case 'Germany': case 'Greece': case 'Portugal': $regex = '/^(EE|EL|DE|PT){0,1}[0-9]{9}$/i'; break; case 'France': $regex = '/^(FR){0,1}[0-9A-Z]{2}[\ ]{0,1}[0-9]{9}$/i'; break; case 'Finland': case 'Hungary': case 'Luxembourg': case 'Malta': case 'Slovenia': $regex = '/^(FI|HU|LU|MT|SI){0,1}[0-9]{8}$/i'; break; case 'Ireland': $regex = '/^(IE){0,1}[0-9][0-9A-Z\+\*][0-9]{5}[A-Z]$/i'; break; case 'Italy': case 'Latvia': $regex = '/^(IT|LV){0,1}[0-9]{11}$/i'; break; case 'Lithuania': $regex = '/^(LT){0,1}([0-9]{9}|[0-9]{12})$/i'; break; case 'Netherlands': $regex = '/^(NL){0,1}[0-9]{9}B[0-9]{2}$/i'; break; case 'Poland': case 'Slovakia': $regex = '/^(PL|SK){0,1}[0-9]{10}$/i'; break; case 'Romania': $regex = '/^(RO){0,1}[0-9]{2,10}$/i'; break; case 'Sweden': $regex = '/^(SE){0,1}[0-9]{12}$/i';

break; case 'Spain': $regex = '/^(ES){0,1}([0-9A-Z][0-9]{7}[A-Z])|([A-Z][0-9]{7}[0-9A-Z])$/i'; break; case 'United Kingdom': $regex = '/^(GB){0,1}([1-9][0-9]{2}[\ ]{0,1}[0-9]{4}[\ ]{0,1}[0-9]{2})|([1-9][09]{2}[\ ]{0,1}[0-9]{4}[\ ]{0,1}[0-9]{2}[\ ]{0,1}[0-9]{3})|((GD|HA)[0-9]{3})$/i'; break; default: return -1; break; } return preg_match($regex, $vat_number); } ?>

Rob 19-Aug-2009 07:03

The following function works well for validating ip addresses <?php function valid_ip($ip) { return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" . "(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $ip); } ?>

KOmaSHOOTER at gmx dot de 09-Aug-2009 01:12

reading files from a dir without "." or ".." <?php $handle = opendir('content/pages/'); $pages = array(); while (false !== ($file = readdir($handle))) { $case=preg_match("/^[.]/",$file,$out, PREG_OFFSET_CAPTURE); //echo($case); if(!$case){ echo("$file<br />"); array_push($pages,$file); } } echo(count($pages)); ?>

matt 08-May-2009 08:07

To support large Unicode ranges (ie: [\x{E000}-\x{FFFD}] or \x{10FFFFF}) you must use the modifier '/u' at the end of your expression.

daniel dot chcouri at gmail dot com 03-May-2009 01:09

Html tags delete using regular expression <?php function removeHtmlTagsWithExceptions($html, $exceptions = null){ if(is_array($exceptions) && !empty($exceptions)) { foreach($exceptions as $exception) { $openTagPattern = '/<(' . $exception . ')(\s.*?)?>/msi'; $closeTagPattern = '/<\/(' . $exception . ')>/msi'; $html = preg_replace( array($openTagPattern, $closeTagPattern), array('||l|\1\2|r||', '||l|/\1|r||'), $html ); } } $html = preg_replace('/<.*?>/msi', '', $html);

if(is_array($exceptions)) { $html = str_replace('||l|', '<', $html); $html = str_replace('|r||', '>', $html); } return $html; } // example: print removeHtmlTagsWithExceptions(<<<EOF <h1>Whatsup?!</h1> Enjoy <span style="text-color:blue;">that</span> script<br /> <br /> EOF , array('br')); ?>

corey [works at] effim [delete] .com 25-Apr-2009 03:52

I see a lot of people trying to put together phone regex's and struggling (hey, no worries...they're complicated). Here's one that we use that's pretty nifty. It's not perfect, but it should work for most non-idealists. *** Note: Only matches U.S. phone numbers. *** <?php // all on one line... $regex = '/^(?:1(?:[. -])?)?(?:\((?=\d{3}\)))?([2-9]\d{2})(?:(?<=\(\d{3})\))? ?(?:(?<=\d{3})[.-])?([2-9]\d{2})[. -]?(\d{4})(?: (?i:ext)\.? ?(\d{1,5}))?$/'; // or broken up $regex = '/^(?:1(?:[. -])?)?(?:\((?=\d{3}\)))?([2-9]\d{2})' .'(?:(?<=\(\d{3})\))? ?(?:(?<=\d{3})[.-])?([2-9]\d{2})' .'[. -]?(\d{4})(?: (?i:ext)\.? ?(\d{1,5}))?$/'; ?> If you're wondering why all the non-capturing subpatterns (which look like this "(?:", it's so that we can do this: <?php $formatted = preg_replace($regex, '($1) $2-$3 ext. $4', $phoneNumber); // or, provided you use the $matches argument in preg_match $formatted = "($matches[1]) $matches[2]-$matches[3]"; if ($matches[4]) $formatted .= " $matches[4]"; ?> *** Results: *** 520-555-5542 :: MATCH 520.555.5542 :: MATCH 5205555542 :: MATCH 520 555 5542 :: MATCH 520) 555-5542 :: FAIL (520 555-5542 :: FAIL (520)555-5542 :: MATCH (520) 555-5542 :: MATCH (520) 555 5542 :: MATCH 520-555.5542 :: MATCH 520 555-0555 :: MATCH (520)5555542 :: MATCH 520.555-4523 :: MATCH

19991114444 :: FAIL 19995554444 :: MATCH 514 555 1231 :: MATCH 1 555 555 5555 :: MATCH 1.555.555.5555 :: MATCH 1-555-555-5555 :: MATCH 520-555-5542 ext.123 :: MATCH 520.555.5542 EXT 123 :: MATCH 5205555542 Ext. 7712 :: MATCH 520 555 5542 ext 5 :: MATCH 520) 555-5542 :: FAIL (520 555-5542 :: FAIL (520)555-5542 ext .4 :: FAIL (512) 555-1234 ext. 123 :: MATCH 1(555)555-5555 :: MATCH

daevid at daevid dot com 06-Mar-2009 11:18

I just learned about named groups from a Python friend today and was curious if PHP supported them, guess what -- it does!!! <?php preg_match("/(?P<foo>abc)(.*)(?P<bar>xyz)/", 'abcdefghijklmnopqrstuvwxyz', $matches); print_r($matches); ?> will produce: Array ( [0] => abcdefghijklmnopqrstuvwxyz [foo] => abc [1] => abc [2] => defghijklmnopqrstuvw [bar] => xyz [3] => xyz ) Note that you actually get the named group as well as the numerical key value too, so if you do use them, and you're counting array elements, be aware that your array might be bigger than you initially expect it to be.

wjaspers4 [at] gmail [dot] com 27-Feb-2009 11:16

I recently encountered a problem trying to capture multiple instances of named subpatterns from filenames. Therefore, I came up with this function. The function allows you to pass through flags (in this version it applies to all expressions tested), and generates an array of search results. Enjoy! <?php /** * Allows multiple expressions to be tested on one string. * This will return a boolean, however you may want to alter this. * * @author William Jaspers, IV <> * @created 2009-02-27 17:00:00 +6:00:00 GMT * @access public * * @param array $patterns An array of expressions to be tested. * @param String $subject The data to test.

* @param array $findings Optional argument to store our results. * @param mixed $flags Pass-thru argument to allow normal flags to apply to all tested expressions. * @param array $errors A storage bin for errors * * @returns bool Whether or not errors occurred. */ function preg_match_multiple( array $patterns=array(), $subject=null, &$findings=array(), $flags=false, &$errors=array() ) { foreach( $patterns as $name => $pattern ) { if( 1 <= preg_match_all( $pattern, $subject, $found, $flags ) ) { $findings[$name] = $found; } else { if( PREG_NO_ERROR !== ( $code = preg_last_error() )) { $errors[$name] = $code; } else $findings[$name] = array(); } } return (0===sizeof($errors)); } ?>

skds1433 at hotmail dot com 19-Feb-2009 02:41

here is a small tool for someone learning to use regular expressions. it's very basic, and allows you to try different patterns and combinations. I made it to help me, because I like to try different things, to get a good understanding of how things work. <?php $search = isset($_POST['search'])?$_POST['search']:"//"; $match = isset($_POST['match'])?$_POST['match']:"<>"; echo '<form method="post">'; echo 's: <input style="width:400px;" name="search" type="text" value="'.$search.'" /><br />'; echo 'm:<input style="width:400px;" name="match" type="text" value="'.$match.'" /><input type="submit" value="go" /></form><br />'; if (preg_match($search, $match)){echo "matches";}else{echo "no match";} ?>

akniep at rayo dot info 30-Jan-2009 11:05

Bugs of preg_match (PHP-version 5.2.5) In most cases, the following example will show one of two PHP-bugs discovered with preg_match depending on your PHP-version and configuration. <?php $text = "test="; // creates a rather long text for ($i = 0; $i++ < 100000;) $text .= "%AB"; // a typical URL_query validity-checker (the pattern's function does not matter for this example) $pattern = '/^(?:[;\/?:@&=+$,]|(?:[^\W_]|[-_.!~*\()\[\] ])|(?:%[\da-fA-F]{2}))*$/'; var_dump( preg_match( $pattern, $text ) ); ?>

Possible bug (1): ============= On one of our Linux-Servers the above example crashes PHP-execution with a C(?) Segmentation Fault(!). This seems to be a known bug (see, but I don't know if it has been fixed, yet. If you are looking for a work-around, the following code-snippet is what I found helpful. It wraps the possibly crashing preg_match call by decreasing the PCRE recursion limit in order to result in a Reg-Exp error instead of a PHP-crash. <?php [...] // decrease the PCRE recursion limit for the (possibly dangerous) preg_match call $former_recursion_limit = ini_set( "pcre.recursion_limit", 10000 ); // the wrapped preg_match call $result = preg_match( $pattern, $text ); // reset the PCRE recursion limit to its original value ini_set( "pcre.recursion_limit", $former_recursion_limit ); // if the reg-exp fails due to the decreased recursion limit we may not make any statement, but PHP-execution continues if ( PREG_RECURSION_LIMIT_ERROR === preg_last_error() ) { // react on the failed regular expression here $result = [...]; // do logging or email-sending here [...] } //if ?> Possible bug (2): ============= On one of our Windows-Servers the above example does not crash PHP, but (directly) hits the recursion-limit. Here, the problem is that preg_match does not return boolean(false) as expected by the description / manual of above. In short, preg_match seems to return an int(0) instead of the expected boolean(false) if the regular expression could not be executed due to the PCRE recursion-limit. So, if preg_match results in int(0) you seem to have to check preg_last_error() if maybe an error occurred.

Alex Zinchenko 11-Dec-2008 02:15

If you need to check whether string is a serialized representation of variable(sic!) you can use this : <?php $string = "a:0:{}"; if(preg_match("/(a|O|s|b)\x3a[0-9]*? ((\x3a((\x7b?(.+)\x7d)|(\x22(.+)\x22\x3b)))|(\x3b))/", $string)) { echo "Serialized."; } else { echo "Not serialized."; } ?> But don't forget, string in serialized representation could be VERY big, so match work can be slow, even with fast preg_* functions.

phil dot taylor at gmail dot com 23-Oct-2008 12:01

If you need to check for and and .uk and all the other crazy domain endings i found the following expression works well if you want to validate an email address. Its quite generous in what it will allow <?php $email_address = ""; if (preg_match("/^[^@]*@[^@]*\.[^@]*$/", $email_address)) { return "E-mail address"; } ?>

Steve Todorov 03-Oct-2008 01:23

While I was reading the preg_match documentation I didn't found how to match an IP.. Let's say you need to make a script that is working with ip/host and you want to show the hostname - not the IP. Well this is the way to go: <?php /* This is an ip that is "GET"/"POST" from somewhere */ $ip = $_POST['ipOrHost']; if(preg_match('/(\d+).(\d+).(\d+).(\d+)/',$ip)) $host = gethostbyaddr($ip); else $host = gethostbyname($ip); echo $host; ?> This is a really simple script made for beginners ! If you'd like you could add restriction to the numbers. The code above will accept all kind of numbers and we know that IP address could be MAX and the example accepts to 999.999.999.999. Wish you luck! Best wishes, Steve

Ashus 12-Sep-2008 03:18

If you need to match specific wildcards in IP address, you can use this regexp: <?php $ip = ''; $cmp = '10.1.??.*'; $cnt = preg_match('/^' .str_replace( array('\*','\?'), array('(.*?)','[0-9]'), preg_quote($cmp)).'$/', $ip); echo $cnt; ?> where '?' is exactly one digit and '*' is any number of any characters. $cmp mask can be provided wild by user, $cnt equals (int) 1 on match or 0.

wjaspers4[at]gmail[dot]com 28-Aug-2008 02:55

I found this rather useful for testing mutliple strings when developing a regex pattern. <?php

/** * Runs preg_match on an array of strings and returns a result set. * @author wjaspers4[at]gmail[dot]com * @param String $expr The expression to match against * @param Array $batch The array of strings to test. * @return Array */ function preg_match_batch( $expr, $batch=array() ) { // create a placeholder for our results $returnMe = array(); // for every string in our batch ... foreach( $batch as $str ) { // test it, and dump our findings into $found preg_match($expr, $str, $found); // append our findings to the placeholder $returnMe[$str] = $found; } return $returnMe; } ?>

Dino Korah AT webroot DOT com 08-Jul-2008 11:11

preg_match and preg_replace_callback doesnt match up in the structure of the array that they fill-up for a match. preg_match, as the example shows, supports named patterns, whereas preg_replace_callback doesnt seem to support it at all. It seem to ignore any named pattern matched.

jonathan dot lydall at gmail dot removethispart dot com 26-May-2008 07:50
Because making a truly correct email validation function is harder than one may think, consider using this one which comes with PHP through the filter_var function ( <?php $email = "someone@domain .local"; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { echo "E-mail is not valid"; } else { echo "E-mail is valid"; } ?>