preg_match正则匹配的字符串长度问题

项目中,用preg_match正则提取目标内容,死活有问题,代码测得死去活来。

后来怀疑PHP 的preg_match有字符串长度限制,果然,发现“pcre.backtrack_limit
”的值默认只设了100000。

解决办法:ini_set('pcre.backtrack_limit', 999999999);

注:这个参数在php 5.2.0版本之后可用。

另外说说关于:pcre.recursion_limit

pcre.recursion_limit是PCRE的递归限制,这个项如果设很大的值,会消耗所有进程的可用堆栈,最后导致PHP崩溃。

也可以通过修改配置来限制:ini_set('pcre.recursion_limit', 99999);

实际项目应用中,最好也对内存进行限定设置:ini_set('memory_limit', '64M');
, 这样就比较稳妥妥嘎。

常用正则表达式

 

元字符及其在正则表达式上下文中的行为: 

 

\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。

 

^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的Multiline 属性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。 

 

$ 匹配输入字符串的结束位置。如果设置了 RegExp 对象的Multiline 属性,$ 也匹配 ’\n’ 或 ’\r’ 之前的位置。 

 

* 匹配前面的子表达式零次或多次。 

 

+ 匹配前面的子表达式一次或多次。+ 等价于 {1,}。 

 

? 匹配前面的子表达式零次或一次。? 等价于 {0,1}。 

 

{n} n 是一个非负整数,匹配确定的n 次。

 

{n,} n 是一个非负整数,至少匹配n 次。 

 

{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗号和两个数之间不能有空格。

 

? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。 

 

. 匹配除 "\n" 之外的任何单个字符。要匹配包括 ’\n’ 在内的任何字符,请使用象 ’[.\n]’ 的模式。 

(pattern) 匹配pattern 并获取这一匹配。 

 

(?:pattern) 匹配pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 

 

(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 

 

(?!pattern) 负向预查,与(?=pattern)作用相反 

 

x|y 匹配 x 或 y。 

 

[xyz] 字符集合。 

 

[^xyz] 负值字符集合。 

 

[a-z] 字符范围,匹配指定范围内的任意字符。 

 

[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。 

 

\b 匹配一个单词边界,也就是指单词和空格间的位置。

 

\B 匹配非单词边界。 

 

\cx 匹配由x指明的控制字符。 

 

\d 匹配一个数字字符。等价于 [0-9]。 

 

\D 匹配一个非数字字符。等价于 [^0-9]。 

 

\f 匹配一个换页符。等价于 \x0c 和 \cL。 

 

\n 匹配一个换行符。等价于 \x0a 和 \cJ。 

 

\r 匹配一个回车符。等价于 \x0d 和 \cM。 

 

\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。 

 

\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 

 

\t 匹配一个制表符。等价于 \x09 和 \cI。 

 

\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。 

 

\w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。 

 

\W 匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。 

 

\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。

 

\num 匹配 num,其中num是一个正整数。对所获取的匹配的引用。 

 

\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 

 

\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 

 

\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 

 

\un 匹配 n,其中 n 是一个用四个十六进制数字表示的Unicode字符。

 

匹配中文字符的正则表达式: [\u4e00-\u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

匹配空白行的正则表达式:\n\s*\r
评注:可以用来删除空白行

匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

匹配首尾空白字符的正则表达式:^\s*|\s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
评注:表单验证时很实用

匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求

匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用

匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
评注:匹配形式如 0511-4405222 或 021-87888822

匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始

匹配中国邮政编码:[1-9]\d{5}(?!\d)
评注:中国邮政编码为6位数字

匹配身份证:\d{15}|\d{18}
评注:中国的身份证为15位或18位

匹配ip地址:\d+\.\d+\.\d+\.\d+
评注:提取ip地址时有用

匹配特定数字:
^[1-9]\d*$    //匹配正整数
^-[1-9]\d*$   //匹配负整数
^-?[1-9]\d*$   //匹配整数
^[1-9]\d*|0$  //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$   //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$   //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$  //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$  //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$   //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$  //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正

匹配特定字符串:
^[A-Za-z]+$  //匹配由26个英文字母组成的字符串
^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串
^[a-z]+$  //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串
^\w+$  //匹配由数字、26个英文字母或者下划线组成的字符串

php正则表达式

1 理解正则表达式


正则表达式是一种可以用于模式匹配的强大工具。简单地说,正则表达式就是一套规则,用于判定其他的元素是否符合它。


举一个简单的例子:在一个用户注册的页面中(例如,一个论坛或者交友网站的注册页面),上面可能有“电子邮件”这一项需要填写。对系统来说,需要判定用户所填写的电子邮件地址是否合法,即是否符合电子邮件地址的规则。利用字符串操作技术可以实现这个功能。


<!--检查电子邮件合法性:validate_email1.php-->
<?php

function validate_email1($email){

    $hasAtSymbol = strpos($email, "@");    //检查是否包含@

    //strpos($mystring,$findme);在$mystring中查找是否存在$findme,有则返回位置,否则返回false;

    $hasDot = strpos($email, ".");         //检查是否包含.

    if($hasAtSymbol && $hasDot && $hasAtSymbol<$hasDot )

        return 1;

    else

        return 0;

}

    echo validate_email1("chen@sjolzy.cn");       //true

    echo validate_email1(chen@sjolzy);             //false

?>

上面代码实现了一个函数validate_email1(),使用字符串操作中的定位字符函数,判断一个字符串是否是一个合法的电子邮件地址的规则。仔细考虑实现的功能,实际上是在判断一个字符串是否具有一定的模式,或者说是否满足一定的规则。在这种情况下,可以使用正则表达式来实现相同的功能。


<!--使用正则表达式检查电子邮件合法性:validate_email2.php-->
<?php

    function validate_email2($email){

        return (int)ereg("^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$", $email);

    }

    echo validate_email2(chen@sjolzy.cn);          //true

    echo validate_email2(chen@sjolzy);        //false

?>

上面实现了具有相同功能的函数validate_email1(),函数使用了一个正则表达式的函数ereg() :以区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。观察ereg()函数的参数“^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$”,容易看出其实际上表示满足这样规则的字符串:以[a-zA-Z]即任意大小写字符串开头,然后紧跟“@”,然后又是任意大小写字母组成的字符串,第4部分是符号“.”,最后仍是任意字符串。这相当于定义了一个字符串的组成规则。


在看过这个示例后,重新来看正则表达式的定义:正则表达式是一种可以用于模式匹配的强大工具。


 2 使用正则表达式


在PHP有6个函数来处理正则表达式,检查一个字符串是否满足一个的规则。它们都把一个正则表达式作为它们的第一个参数,语法如下。


    bool ereg(string pattern, string string [, array regs]):最常用的正则表达式函数, 搜索跟正则表达式pattern匹配的一个字符串。区分大小写。搜索到返回true,否则返回false。
 

     string ereg_replace(string pattern, string replacement, string string):搜索跟正则表达式pattern匹配的一个字符串,并用新的字符串代替所有这个表达式出现的地方。


     bool eregi(string pattern, string string [, array regs]):搜索跟正则表达式pattern匹配的一个字符串。不区分大小写。搜索到返回true,否则返回false。


     string eregi_replace(string pattern, string replacement, string string):和ereg_replace有着一样的搜索-替换功能,不过忽略大小写


     arraysplit(string pattern, string string [, int limit]):搜索和正则表达式匹配的字符串,区分大小写并且以字符串集合的方式返回匹配结果。


     arrayspliti(string pattern, string string [, int limit]):搜索和正则表达式匹配的字符串,不区分大小写,并且以字符串集合的方式返回匹配结果。

    介绍了PHP的正则表达式函数及其功能。要了解它们的具体使用方法,则要首先了解正则表达式的构造。


3 构造正则表达式:


    如前所述,在匹配一个字符串到正则表达式之前,必须先构造正则表达式。

    1).定义头部规则
   SPHP用“^”定义字符串头部的规则,例如:“^hello”即定义头部为“hello”的字符串,结合上一节所介绍的函数,代码<?php echo ereg("^hello", "hello world!"); ?>    //true将返回“true”,因为待验证的字符串“hello word!”满足规则:以“hello”开头。而<?php echo ereg("^hello", "i say hello world"); ?>    //false将返回 false,因为hello不在字符串”I say hello world”的头部。

    2).定义尾部规则
    <?PHP用“$”定义字符串尾的规则,例如:“world$”即定义尾部为“world”的字符串,代码

    <?php echo ereg("world$", "hello world!"); ?>        //true

    将返回“true”,因为待验证的字符串“hello word!”满足规则:以“world”结尾。而

    <?php echo ereg("world$", "i say hello php"); ?>    //false

    将返回 false,因为world不在字符串”I say hello     php”的尾部。

    3).定义包含任意字符规则$ 
    PHP用“.”定义包含任意字符的规则,例如:“.”即定义包含任意字符的字符串,代码

    <?php echo ereg(".", "something"); ?>        //true

    将返回“true”,因为待验证的字符串“something”满足规则:包含任意字符。而

    <?php echo ereg(".", ""); ?>                //false

    将返回 false,因为空串不包含任意字符。

    4).定义包含字符数目规则
    使用大括号“{n}”定义包含n个任意字符,“{m,n}”定义包含m到n范围内的任意字符。

    例如“.{3}”定义包含或超过3个连续任意字符的字符串,“.{1,3}”定义包含1到3个字符的字符串。代码

    <?php echo ereg(".{3}", "abcd"); ?>        //true
    <?php echo ereg(".{1,3}", "aa"); ?>        //true

    都将返回“true”,因为待验证的字符串“aaa”满足规则:包含3个字符。而

    <?php echo ereg(".{4}", "aaa"); ?>        //false

    将返回 false。

    “.”也可以结合“^”和“$”使用,例如“.{3}$”定义了以3个字符结尾的字符串,“^.{3}”定义了以三个连续字符开头的字符串。代码

    <?php echo ereg(".{3}$", "baaa"); ?>        //true

    将返回“true”,因为待验证的字符串“baaa”满足规则:以3个连续字符结尾。而

    <?php echo ereg(".{3}$", "ab"); ?>          //false

    将返回 false。)

    5).定义包含0~n个字符规则
    PHP用“*”定义包含0~n个字符的规则,例如:“a*”即定义包含0~n个字符的字符串,代码

    <?php echo ereg("a*", "aaa"); ?>        //true

    将返回“true”,因为待验证的字符串“aaa”满足规则:包含0~n个字符“a”。而

    <?php echo ereg("a*", "bbb"); ?>        //true

    也将返回 true,因为待验证的字符串“bbb”也满足规则:包含0~n个字符“a”。

    6).定义包含1~n个字符规则
    PHP用“+”定义包含1~n个字符的规则,例如:“a+”即定义包含1~n个字符“a”的字符串,代码

    <?php echo ereg("a+", "aaa"); ?>        //true

    将返回“true”,因为待验证的字符串“aaa”满足规则:包含1~n个字符“a”。而

    <?php echo ereg("a+", "bbb"); ?>        //false

    将返回 false,因为待验证的字符串“bbb”不满足规则:包含1~n个字符“a”。

    *7).定义包含0或1个字符规则
    PHP用“?”定义包含0或1个字符的规则,例如:“a?”即定义包含0或1个字符“a”的字符串,代码

    <?php echo ereg("a?", "a"); ?>        //true
    <?php echo ereg("a?", "bb"); ?>       //true

    将返回“true”,因为待验证的字符串“a”和“bb”都满足规则:包含0或1个字符“a”。而

    <?php echo ereg("a?", "aa"); ?>    //true

   //(有错) 将返回false,因为待验证的字符串“bbb”不满足规则:包含0或1个字符“a”。

    8).定义包含某范围的字符规则
    PHP用方括号“[start-end]”定义包含start-end范围内任意字符的规则,例如:“[a-z]”即定义包含a到z范围内任意字符的字符串,代码

    <?php echo ereg("^[a-z]+$", "abc"); ?>    //true

    将返回“true”,因为待验证的字符串“abc”满足规则:包含1~n个字符a~z范围内任意字符。

    <?php echo ereg("^[a-z]+$", "ABC"); ?>    //false

    将返回 false,因为待验证的字符串“ABC”不满足规则:包含1~n个字符“a”。

    9).定义包含某范围的词规则
    PHP用圆括号“(word1|word2|…)”定义包含word1、word2、…的任意字符串的规则,例如:“(wang|zhang)”即定义包含“wang”或“zhang”的任意字符的字符串,代码

    <?php echo ereg("^(wang|zhang)+$", "wang and zhang"); ?>    //true

    将返回“true”,因为待验证的字符串“wang and zhang”满足规则:以“wang”或“zhang”开头。

    <?php echo ereg("^(wang|zhang)+$", "shi and jing"); ?>        //false

    将返回 false,因为待验证的字符串“shi and jing”不满足规则:以“wang”或“zhang”开头。

    10).空格字符的处理
    空格字符可以简单的处理为普通字符“ ”,但在实际使用中常用“[[:space]]”来代替,这样在字符串中更加易读。例如:“I[[:space]]am”表示为“I am”。

    11).特殊字符的处理
    因为一些字符要用在一个正则表达式语法上,像(wang|zhang)中的圆括号,需要屏蔽掉这些字符,使之成为字符串的一部分,而不是具有功能性的表达式的一部分。用转义字符,即反斜杠“\”可以实现这种转换,例如:

    <?php echo ereg("^[a-zA-z]+\|[a-zA-z]+$", "wang|zhang"); ?>

    在正则表达式中,需要转义的字符包括:^, $, (, ), ., [, |, *, ?, +, \ and {。

    本节全面的介绍了如何构造一个正则表达式,即如何定义一个字符串组成规则。下一节,将给出一系列例子,通过例子,将进一步熟悉上述规则构造方法。

4 示例1验证


    本小节实现利用PHP正则表达式验证URL合法性的示例。一个合法的URL如:

    <a href="//sjolzy.cn" target="_blank">sjolzy.cn</a>

    其构造规则为:[协议]://[www].[域名].[com|net|org…]

    根据上一小节的构造正则表达式,可以构造下面的规则。

    "^http://(www\ .)?.+\ .(com|net|org)$"    

    其中,"^http://”定义能匹配规则的字符串开头是"http://";"(www\ .)?"表示随后应该是0-1个“www”;而“.+”表示任意字符串;然后是一个“.”,转义字符“\”表明其仅仅是一个字符;最后的“(com|net|org)$”表明以com、net、org中其中一个结尾,此处,只列出这3种情况。完成验证URL合法性的函数如下所示。

    <!--使用正则表达式检查URL合法性:validate_url.php-->

    <?php

        function isValidDomain($domainName)

        {

            return(int)ereg("^(http|ftp)://(www\.)?.+\.(com|net|org)$",$domainName);

        }

        echo isValidDomain(http://www.sjolzy.cn);    //1

        echo isValidDomain("//sjolzy.com");    //1

        echo isValidDomain("http://www.sjolzy.fr");    //0

        echo isValidDomain("www.sjolzy.com");    //0

    ?>

5 示例2验证电话号码

    本小节实现利用PHP正则表达式验证北京市电话号码合法性的的示例。合法的号码如:+86 010xxxxxxxx,其构造规则为:[+86] [010][八位数字]。

    根据上一小节的构造正则表达式,可以构造下面的规则。

    “^\+86[[:space:]]010[0-9]{8}$

    其中,“^\+86”定义能匹配规则的字符串开头是“+86”;“[[:space:]]”表示随后1个空格;而“[0-9]{8}$”表明以8个数字结尾。
    完成验证北京市电话号码合法性的函数如下所示。

    <!--使用正则表达式检查北京电话号码合法性:validate_phone.php-->

    <?php

        function isValidPhone($phoneNum)

        {

            echo (int)ereg("^\+86[[:space:]]010[0-9]{8}$", $phoneNum);

        }

        echo isValidPhone("+86 01012345678");          //1

        echo isValidPhone("+86 010123456789");        //0

        echo isValidPhone("+86 0101234567a");          //0

    ?>