欢迎您的光临,本博所发布之文章皆为作者亲测通过,如有错误,欢迎通过各种方式指正。

教程  php基础(九)--正则表达式、应用和实例汇总详解

PHP学习 本站 686 1评论

1.正则表达式介绍


正则表达式简介

正则表达式是用于描述字符排列和匹配模式的一种语法规则。它主要用于字符串的模式分割、匹配、查找及替换操作。到目前为止,我们前面所用过的精确(文本)匹配也是一种正则表达式。

在PHP中,正则表达式一般是由正规字符和一些特殊字符(类似于通配符)联合构成的一个文本模式的程序性描述。


PHP中,正则表达式的三个作用:

· 匹配,也常常用于从字符串中析取信息。

· 用新文本代替匹配文本。

· 将一个字符串拆分为一组更小的信息块。


在PHP中有两套正则表达式函数库,两者功能相似,只是执行效率略有差异:

· 一套由PCRE(Perl Compatible Regular Expression)库提供的。使用“preg_”为前缀命名的函数;

· 一套由POSIX(Portable Operating System Interface of Unix )扩展提供的。使用以“ereg_”为前缀命名的函数;

PCRE来源于Perl语言,而Perl是对字符串操作功能最强大的语言之一,PHP的最初版本就是由Perl开发的产品。

PCRE语法支持更多特性,比POSIX语法更强大。


2.正则表达式的语法规则


php正则表达式是由原子(普通文本字符,例如字符a到z)、特殊字符(元字符(具有特殊含义的字符),例如*、+和?等)、以及模式修正符三部分组成的文字模式。


一个最简单正则表达式至少包含一个原子。将下面的正则表达式拆分如下:

'/<a.*?(?:|\\t|\\r|\\n)?href=[\"]?(.+?)[\"]?(?:(?:|\\t|\\r|\\n)+.*?)?>(.+?)<\/a.*?>/sim'

· 定界符:两个斜线”/”。

· 原子用到了< a href = ‘ “ / >等普通字符和\t \r \n等转义字符

· 元字符使用了 [] () | . ? * + 等具有特殊含义的字符

· 用到了模式修正符是在定界符最后一个斜线之后的三个字符: s i m


1)定界符

在程序语言中,使用与Perl兼容的正则表达式,通常都需要将模式表达式放入定界符之间,如“/”。

作为定界符常使用反斜线“/”,如“/apple/”。用户只要把需要匹配的模式内容放入定界符之间即可。作为定界的字符也不仅仅局限于“/”。除了字母、数字和斜线“\”以外的任何字符都可以作为定界符,像 ‘#’、’|’、’!’ 等都可以的。

/</\w+>/ --使用反斜线作为定界符合法

|(\d{3})-\d+|Sm --使用竖线”|”作为定界符合法

!^(?i)php[34]! --使用竖线”!”作为定界符合法

{^\s+(\s+)?$} --使用竖线”}”作为定界符合法

/href=‘(.*)’ --非法定界符,缺少结束定界符

1-\d3-\d3-\d4| --非法定界符,缺少其实定界符


2)行定位符(^ 和$

行定位符是用来描字符串的边界。”^”表示行的开始;”$”表示行的结束。如:

^tm: 匹配字符串中以tm开头;

tm$:匹配字符串以tm结尾的。


3)单词定界符(\b,\B

从上面的列子可以匹配tm在字符串中出现的任何位置。现在要匹配的是单词tm,而不是单词的一部分。这时用单词定界符\b,表示要查找的是一个完整的单词。如:

\btm\b: 匹配单词tm

还有个大写的\B,意思相反。它匹配的字符串不能是一个完整的单词,而是其他单词或子串的一部分。


4)字符类([]

正则表达式是区分大小写的,如果要忽略大小写可以使用方括号表示“[]”只要匹配的字符串出现在方括号内,即表示匹配成功。一个方括号只能匹配一个字符。如:

要匹配子串tm不区分大小写,应该这么写:[Tt][Mm].


5)选择字符(|)

|该字符可以理解为或。上面的例子可以写成 T|tM|m:表示以字母T或t开头,后面接着一个字母M或m

使用[]和|的区别在于[]只能匹配单个字符,而|可以匹配任意长度的字符串。上面的例子也可以写成 TM|tm|Tm|tM


6)连字符(-

变量的命名规则只能是以字母和下划线开头。这样一来,如果要使用正则表达匹配变量名的第一个字母,要写为:

[a,b,c,d…A,B,C,D],很长,如果用连字符就写成[a-zA-Z]


7)排除字符([^]

如果要匹配不符合命名规则的变量,正则表达式提供了“^”,这里的^要放在括号中。如:

[^a-zA-Z]:匹配不是以字母和下划线开头的变量名


8)限定符(? *  + {n,m}

image001.png

如:go{2,20}gle  //匹配o字母2-20次。


9)点号字符(.

如匹配5-10个以s开头、t结尾的单词。可以通过点号来实现

点号可以匹配出换行符(\n)以外的任意的一个字符。如:

^s.t$:匹配以s开头,t结尾中间包含一个字母的字符。

^r.s.*t$:匹配第一个字母是r,第三个字母是s,以t结尾的单词。


10)转义符(\

如果要匹配127.0.0.1,就要用到转义符\匹配“.”,而不能直接使用“.”,否则点表示任意一个字符。如:

[0-9]{1,3}(\.[0-9]{1,3}){3}


11)反斜线(\

反斜线除了转义符以外,还有其他功能。

反斜线可以将一些不可打印的字符打印出来,如图:

image003.png

指定预定于字符集,如图

image005.png

定义断言,其中已经了解过\b,\B,如图

image007.png


12)括号字符(())

小括号字符的第一个作用就是可以改变限定符的作用范围,如“|”,“*”,“^”等

如:(thir|four)th 表示匹配thirth或fourth

小括号的第二个作用就是分组,也即是子表达式如(\.[0-9]{1,3}){3},就是对表达式(\.[0-9]{1,3})进行3次匹配。


13)反向引用

反向引用,就是依靠子表达式的“记忆”功能来匹配连续出现的子串和字母。如匹配连续的两个it,首先将it作为分组,然后在后面加上“\1”即可。格式为:

(it)\1

如果匹配的字符串不固定,那么就将括号内的子串写成一个正则表达式。如果使用了多个分组,那么可以用“\1”, “\2”来表示每个分组(顺序是从左到右),如:

([a-z])([A-Z]) \1\2

除了可以使用数字来表示分组,还可以自己来定义分组名称,如:

(?P <分组名>…)

要想反向引用该分组,格式如下:

(?=分组名)


【关于反向引用的详细介绍请看文章:PHP正则表达式--反向引用。】


模式修饰符

模式修饰符的作用就是规定正则表达式应该如何解释应用。不同的语言有自己的模式设置。

image009.png


3.PHP中POSIX正则表达式的函数


ereg()函数和eregi()函数

语法:bool  ereg ( string  $pattern , string  $string [, array &$regs ] )

区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。


如果找到与 pattern 中圆括号内的子模式相匹配的子串并且函数调用给出了第三个参数 regs,则匹配项将被存入 regs 数组中。$regs[1] 包含第一个左圆括号开始的子串,$regs[2] 包含第二个子串,以此类推。$regs[0] 包含整个匹配的字符串。


提示: 直到 PHP 4.1.0 为止,$regs 将被填充为正好十个单元,即使实际匹配的子串少于十个。这并不影响 ereg() 匹配更多子串的能力。如果没有找到匹配,则 $regs 不会被 ereg() 更改。

如果在 string 中找到 pattern 模式的匹配则返回 所匹配字符串的长度,如果没有找到匹配或出错则返回 FALSE。如果没有传递入可选参数 regs 或者所匹配的字符串长度为 0,则本函数返回 1。

提示使用 Perl 兼容正则表达式语法的 preg_match() 函数通常是比 ereg() 更快的替代方案。

eregi() 函数的用法同上,只是不区分大小写

例:

$ereg = '^[$][[:alpha:]_][[:alnum:]]*';
ereg($ereg,'$_name',$register);
var_dump($register);

输出:array(1) { [0]=> string(6) "$_name" }


ereg_replace()函数和eregi_replace()函数

语法:string  ereg_replace ( string  $pattern , string  $replacement , string  $string )

本函数在 string 中扫描与 pattern 匹配的部分,如果匹配成功,并将其替换为 replacement

返回替换后的字符串。(如果没有可供替换的匹配项则会返回原字符串。)


如果 pattern 包含有括号内的子串,则 replacement 可以包含形如 \digit 的子串,这些子串将被替换为数字表示的的第几个括号内的子串;\0 则包含了字符串的整个内容。最多可以用九个子串。括号可以嵌套,此情形下以左圆括号来计算顺序。

如果未在 string 中找到匹配项,则 string 将原样返回。

eregi_replace()函数的用法同上,只是不区分大小写

$ereg = 'tm';//要匹配的字串
$str = 'hello,tm,Tm,tM.';//要查找的文本
$rep_str = eregi_replace($ereg,'TM',$str);//使用eregi_replace()函数进行替换
echo $rep_str;

输出:hello,TM,TM,TM.


split()函数和spliti()函数

语法:array  split / spliti (string  $pattern, string  $string [, int $limit]) 

使用表达式pattern来分隔字符串string,如果有参数limit,那么数组最多有limit个元素,剩余部分都写到最后一个数组元素中。如果函数错误,则返回false。前者区分大小写。

$ereg = 'is';
$str = 'This is a register book.';
$arr_str = spliti($ereg,$str);
var_dump($arr_str);

输出:array(4) { [0]=> string(2) "Th" [1]=> string(1) " " [2]=> string(6) " a reg" [3]=> string(9) "ter book." }


另外有个分割字符串的函数,前面已讲述过。用法如下:

语法:array  explode ( string  $separator, string  $string [, int $limit]) 

请注意两个函数的第一个参数string $pattern和string separator,一个是$pattern说明是正则字符串,一个是$separator是普通字符串。


4.PHP中POSIX正则表达式的函数


PHP中PCRE正则表达式的函数有7个。从效率和语法上都比POSIX好。


preg_grep()函数

语法定义:array  preg_grep (string  $pattern, array  $input)

PHP函数preg_grep()返回一个数组,使用$input数组中元素一一匹配表达式$pattern对于输入数组$input中的每个元素,preg_grep()也只进行一次匹配。如:

$preg = '/\d{3,4}-?\d{7,8}/';
$arr = array('043212345678','0431-7654321','12345678');
$preg_arr = preg_grep($preg,$arr);
var_dump($preg_arr);

输出:array(2) { [0]=> string(12) "043212345678" [1]=> string(12) "0431-7654321" }


preg_match()函数和preg_match_all()函数

语法:preg_match (pattern , subject, matches)

在字符串subject中匹配表达式pattern,函数返回匹配的次数。如果有数组matches,那么每次匹配的结果将被存储到数组matches中。

preg_match() 函数用于进行正则表达式匹配,成功返回 1 ,否则返回 0 。

preg_match() 匹配成功一次后就会停止匹配,如果要实现全部结果的匹配,则需使用 preg_match_all() 函数

$str = 'This is an example!';
$preg = '/\b\w{2}\b/';
$num1 = preg_match($preg,$str,$str1);
echo $num1.'<br>';
var_dump($str1);
$num2 = preg_match_all($preg,$str,$str2);
echo '<br>'.$num2.'<br>';
var_dump($str2);

输出:

array(2) { [0]=> string(12) "043212345678" [1]=> string(12) "0431-7654321" } 

1

array(1) { [0]=> string(2) "is" } 

2

array(1) { [0]=> array(2) { [0]=> string(2) "is" [1]=> string(2) "an" } }


preg_quote()函数

转义正则表达式函数,语法如下:

string  preg_quote ( string  $str [,  string  $delimiter = NULL ] )

将字符串str中所有特殊字符进行转义。如果有delimiter参数,那么该参数所包含的字符串也将被转义。函数返回转义后的子串。

preg_quote()需要参数str并向其中 每个正则表达式语法中的字符前增加一个反斜线. 这通常用于你有一些运行时字符串 需要作为正则表达式进行匹配的时候.

正则表达式特殊字符有: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : - @ #

$str = '!、$、^、*、+、.、[、]、\\、/、b、<、>';
$str2 = 'b';  //输出常用的特殊字符,并将字母b也作为特殊字符输出。
$match_one = preg_quote($str,$str2);
echo $match_one;

输出:\!、\$、\^、\*、\+、\.、\[、\]、\\、/、\b、\<、\>


preg_replace()函数

语法:preg_replace (pattern , replacement , subject, limit, count )

参数描述

· pattern 正则表达式(字符串或字符串数组)

· replacement 用于替换的字符串或字符串数组

· subject 要进行搜索和替换的字符串或字符串数组。如果subject是一个数组, 搜索和替换 回在subject 的每一个元素· · 上进行, 并且返回值也会是一个数组.

· limit可选。 每个模式在每个subject上进行替换的最大次数。默认是 -1(无限)。

· cout可选。 完成的替换次数

返回值:

· 如果subject是一个数组, preg_replace()返回一个数组, 其他情况下返回一个字符串.

· 如果匹配被查找到, 替换后的subject被返回, 其他情况下 返回没有改变的subject. 如果发生错误, 返回NULL .

$string = 'April 15, 2003';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,$3';
// $1对应(\w+),${1}1是区别$11,说明是$1和1不是$11,$3对应(\d+)
echo preg_replace($pattern, $replacement, $string);

输出:April1,2003

$patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/', '/^\s*{(w+)}\s*=/');
$replace = array ('\3/\4/\1\2', '$\1 =');
// \3对应(\d{1,2}),\4对应后一个(\d{1,2}),
echo preg_replace($patterns, $replace, '{startDate} = 1999-5-27');

输出:{startDate} = 5/27/1999


preg_replace_callback()函数

preg_replace_callback()执行一个正则表达式搜索并且使用一个回调进行替换

语法:mixed  preg_replace_callback ( mixed  $pattern , callback  $callback , mixed  $subject [, int $limit = -1 [, int &$count ]] )

这个函数的行为除了 可以指定一个callback替代replacement进行替换 字符串的计算, 其他方面等同于preg_replace()

参数

· pattern  要搜索的模式, 可以使字符串或一个字符串数组.

· callback  一个回调函数, 在每次需要替换时调用, 调用时函数得到的参数是从subject 中匹配到的结果. 回调函数返回真正参与替换的字符串.


你可能经常会需要callback函数而 仅用于preg_replace_callback()一个地方的调用. 在这种情况下, 你可以 使用匿名函数来定义一个匿名函数作 为preg_replace_callback()调用时的回调. 这样做你可以保留所有 调用信息在同一个位置并且不会因为一个不在任何其他地方使用的回调函数名称而污染函数名称空间.

function c_back($str){
$str = "<font color=$str[1]>$str[2]</font>";
return $str;
}
$string = '[color=blue]字体颜色[/color]';
echo preg_replace_callback('/\[color=(.*)\](.*)\[\/color\]/i',"c_back",$string);

输出:字体颜色

例2:

// 将文本中的年份增加一年.
$text = "April fools day is 04/01/2002 ";
$text.= "Last christmas was 12/24/2001 ";
// 回调函数
function next_year($matches)
{
  // 通常: $matches[0]是完成的匹配
  // $matches[1]是第一个捕获子组的匹配
  // 以此类推
  return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
            "|(d{2}/d{2}/)(d{4})|",
            "next_year",
            $text);

输出:April fools day is 04/01/2002 Last christmas was 12/24/2001


preg_split()函数

preg_split  通过一个正则表达式分隔字符串,该函数与split () 函数的用法相同

语法:array  preg_split ( string  $pattern , string  $subject [, int $limit = -1 [, int $flags = 0 ]] )

通过一个正则表达式分隔给定字符串.

参数

· pattern   用于搜索的模式, 字符串形式.

· subject  输入字符串

· limit  如果指定, 将限制分隔得到的子串最多只有limit个, 返回的最后一个 子串将包含所有剩余部分.limit值为-1, 0· 或null时都代表"不限制", 作为php的标准, 你可以使用null跳过对flags的设置.


flags可以是任何下面标记的组合(以位或运算|组合):

    1.PREG_SPLIT_NO_EMPTY 如果这个标记被设置, preg_split()将进返回分隔后的非空部分.

    2.PREG_SPLIT_DELIM_CAPTURE 如果这个标记设置了, 用于分隔的模式中的括号表达式将被捕获并返回.

    3.PREG_SPLIT_OFFSET_CAPTURE  如果这个标记被设置, 对于每一个出现的匹配返回时将会附加字符串偏移量. 注意: 这将会改变返回数组中的每一个元素, 使其每个元素成为一个由第0 个元素为分隔后的子串, 第1个元素为该子串在subject 中的偏移量组成的数组.

返回值

返回一个使用pattern边界分隔subject后得到 的子串组成的数组.

例:

$str = 'hypertext language programming';
$chars = preg_split('/ /', $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
print_r($chars);

输出:Array ( [0] => Array ( [0] => hypertext [1] => 0 ) [1] => Array ( [0] => language [1] => 10 ) [2] => Array ( [0] => programming [1] => 19 ) )


preg_filter()函数

preg_filter 执行一个正则表达式搜索和替换

语法:mixed preg_filter ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

preg_filter()等价于preg_replace() 除了它仅仅返回(可能经过转化)与目标匹配的结果. 这个函数怎样工作的更详细信息请阅读 preg_replace()文档.

返回值  

· 如果subject是一个数组, 返回一个数组, 其他情况返回一个字符串.

· 如果没有找到匹配或者发生了错误, 当subject是数组 时返回一个空数组, 其他情况返回NULL.


preg_last_error ()函数

preg_last_error — 返回最后一个PCRE正则执行产生的错误代码

语法:int  preg_last_error ( void )

返回最后一次PCRE正则执行的错误代码.

preg_match('/(?:D+|<d+>)*[!?]/', 'foobar foobar foobar');
if (preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR) {
    print 'Backtrack limit was exhausted!';
}

以上例程会输出:

 Backtrack limit was exhausted!


5.正则表达式在php中应用


1)php中字符串匹配

所谓的字符串匹配,言外之意就是判断一个字符串中,是否包含或是等于另一个字符串。如果不使用正则,我们可以使用php中提供了很多方法进行这样的判断。

 

· 不使用正则匹配--strstr函数 

string strstr ( string haystack,mixedneedle [, bool $before_needle = false ]) 

注1:haystack是当事字符串,needle是被查找的字符串。该函数区分大小写。

注2:返回值是从needle开始到最后。

注3:关于$needle,如果不是字符串,被当作整形来作为字符的序号来使用。

注4:before_needle若为true,则返回前东西。


stristr函数与strstr函数相同,只是它不区分大小写

--strpo函数 

int strpos ( string haystack,mixedneedle [, int $offset = 0 ] ) 

注1:可选的 offset 参数可以用来指定从 haystack 中的哪一个字符开始查找。返回的数字位置是相对于 haystack 的起始位置而言的。

--stripos -查找字符串首次出现的位置(不区分大小定)

--strrpos -计算指定字符串在目标字符串中最后一次出现的位置

--strripos -计算指定字符串在目标字符串中最后一次出现的位置(不区分大小写)

 

· 使用正则进行匹配

在php中,提供了preg_math()和preg_match_all函数进行正则匹配。关于这两个函数原型如下:

int preg_match|preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] ) 

搜索subject与pattern给定的正则表达式的一个匹配. 

参数

· pattern:要搜索的模式,字符串类型。 

· subject :输入字符串。 

· matches:如果提供了参数matches,它将被填充为搜索结果。 matches[0]将包含完整模式匹配到的文本,· matches[1]将包含第一个捕获子组匹配到的文本,以此类推。 

· flags:flags可以被设置为以下标记值:PREG_OFFSET_CAPTURE 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。 

· offset:通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。 

返回值

preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为 preg_match()在第一次匹配后 将会停止搜索。 preg_match_all()不同于此,它会一直搜索subject直到到达结尾。 如果发生错误 preg_match()返回 FALSE。

 

实例:

--实例1(判断字符串”http://blog.csdn.net/hsd2012“中是否包含csdn?)

解法一(不适用正则): 

如果不适用正则,我们使用strstr或者strpos中任意一个都可以,在此,我将使用strstr函数,代码如下:

$str='http://blog.csdn.net/hsd2012';
function checkStr1($str,$str2)
{
    return strstr1($str,$str2)?true:false;
}
echo checkStr($str,'csdn');

解法二:使用正则 

因为我们只需要判断是否存在即可,所以选择preg_match。

$str='http://blog.csdn.net/hsd2012';
$pattern='/csdn/';
function checkStr2($str,$str2)
{
    return preg_match($str2,$str)?true:false;
}
echo checkStr2($str,$pattern);


--实例2(考察单词定界符) 

判断字符串”I am a good boy”中是否包含单词go 

首先判断是单词,而不是字符串,因此比较的时候,需要比较是否包含’ go ‘,即在字符串go前后有一个空格。 

解析:如果使用非正则比较,只需要调用上面的checkStr1()函数即可,注意,第二个参数前后要加一个空格,即’ go ‘。如果使用正则, 

我们可以考虑使用单词定界符\b,那么$pattern=’/\bgo\b/’;然后调用checkStr2函数即可.


--实例3(考察反向引用) 

判断字符串”I am a good boy”中是否包含3个相同的字母 

解析:此时,如果我们不使用正则,将会很难判断,因为字母太多了,我们不可能去将所有字母分别与该字符串比较,那样工作量也比较大。这时候涉及到了正在的反向引用。在php正则表达式中,通过\n,来表示第n次匹配到的结果。如\5代表第五次匹配到的结果。那么本题的$pattern='/(\w).*\1.*\1/'; 

主要注意的是,在使用反向匹配的时候都需要使用(),反向匹配时,匹配()里面出现的字符或字符串。

 

2)php中字符串替换

 

· 不使用正则

php中当替换字符串的时候,如果不适用正则,我们通常使用substr、mb_substr、str_replace、substr_replace关于这几个函数区别如下表。


函数符功能描述
str_replace(find,replace,string,count)使用一个字符串替换字符串中的另一些字符。find 必需。规定要查找的值。replace 必需。规定替换 find 中的值的值。string 必需。规定被搜索的字符串。count 可选。一个变量,对替换数进行计数。
substr_replace(string,replacement,start,length)把字符串的一部分替换为另一个字符串。适合用于替换自定位置的字符串。string 必需。规定要检查的字符串。replacement 必需。规定要插入的字符串。start 必需。规定在字符串的何处开始替换。


· 使用正则

如果使用正则替换,php中提供了preg_replace _callback和preg_replace 函数,preg_replace 原型如下: 

mixed preg_replace ( mixed pattern,mixedreplacement , mixed subject[,intlimit = -1 [, int &count]])

函数功能描述:在字符串subject中,查找pattern,然后使用replacement 去替换,如果有limit则代表限制替换limit次。pregreplacecallback与pregreplace功能相识,不同的是pregreplaceback使用一个回调函数callback来代替replacement.


--例1

将字符串”hello,中国”中的hello替换为′你好′;如果不是用正则:str=’hello,中国’; 

str=strreplace(′hello′,′你好′,str) 

或是使用str=substrreplace(str,’你好’,0,5) 

使用正则

pattern=′/hello/′;str=preg_replace (pattern,′你好′,str); 

--例2 

去除字符串”gawwenngeeojjgegop”中连续相同的字母

$str='gawwenngeeojjgegop';
$pattern='/(.)\1/';
$str=preg_replace($pattern,'',$str);

解析:当然这样可能会遇到,当第一次去除了重复了字符串后,又出来重复的字符串。如字符串味’gewwenngeeojjgegop’,针对这中问题,当然,这样的话,通过判断,继续替换下去。

--例3 

将字符串中”age13gegep3iorji65k65k”;中出现的连续两个数字改为第二个数字,如字符串中13被改为3

$str='age13gegep3iorji65k65k';
$pattern='/(\d)(\d)/';
$str=preg_replace($pattern,'$2', $str);

解析:$n在正则表达式外使用反向引用。n代表第几次匹配到的结果。

 

3)php中字符串分割

 

· 不使用正则

php提供了explode函数去分割字符串,与其对应的是implode。关于explode原型如下: 

array explode ( string delimiter,stringstring [, int $limit ] ) 

delimiter:边界上的分隔字符。 

string:输入的字符串。 

limit:如果设置了 limit 参数并且是正数,则返回的数组包含最多 limit 个元素,而最后那个元素将包含 string 的剩余部分。如果 limit 参数是负数,则返回除了最后的 -limit 个元素外的所有元素。如果 limit 是 0,则会被当做 1。


· 使用正则

关于通过正则表达式进行字符串分割,php提供了split、preg_split 函数。preg_split() 函数,通常是比 split() 更快的替代方案。 

array preg_split ( string pattern,stringsubject [, int limit=−1[,intflags = 0 ]] )

--例题 

将字符串 ‘http://blog.csdn.net/hsd2012/article/details/51152810‘按照’/’进行分割 

解法一:

$str='http://blog.csdn.net/hsd2012/article/details/51152810';
$str=explode('/', $str);

解法二:

$str='http://blog.csdn.net/hsd2012/article/details/51152810';
$pattern='/\//';  /*因为/为特殊字符,需要转移*/
$str=preg_split ($pattern, $str);


4)php中贪婪匹配与惰性匹配


--贪婪匹配:就是匹配尽可能多的字符。 

比如,正则表达式中m.*n,它将匹配最长以m开始,n结尾的字符串。如果用它来搜索manmpndegenc的话,它将匹配到的字符串是manmpndegen而非man。可以这样想,当匹配到m的时候,它将从后面往前匹配字符n。

--懒惰匹配:就是匹配尽可能少的字符。 

有的时候,我们需要并不是去贪婪匹配,而是尽可能少的去匹配。这时候,就需要将其转为惰性匹配。怎样将一个贪婪匹配转为惰性匹配呢?只需要在其后面添加一个”?”即可。如m.*?n将匹配manmpndegenc,匹配到的字符串是man。

函数符描述
*?零次或多次,但尽可能少的匹配
+?一次或多次,但尽可能少的匹配
??0次或1次,但尽可能少的匹配
{n,}?至少n次,但尽可能少的匹配
{n,m}?n到m次 ,但尽可能少的匹配

 

5)php正则表达式之回溯与固态分组

 

回溯

首先我们需要清楚什么是回溯,回溯就像是在走岔路口,当遇到岔路的时候就先在每个路口做一个标记。如果走了死路,就可以照原路返回,直到遇见之前所做过的标记,标记着还未尝试过的道路。如果那条路也走不能,可以继续返回,找到下一个标记,如此重复,直到找到出路,或者直到完成所有没有尝试过的路。首先我们看例题

$str='aageacwgewcaw';
$pattern='/a\w*c/i';
$str=preg_match($pattern, $str);

看到上面的程序,可能都清楚是什么意思,就是匹配$str是否包含这样一个由”a+0个或多个字母+c”不区分大小写的字符串。但是至于程序怎样去匹配的呢?匹配的过程中,回溯了多少次呢?

匹配过程接下来操作描述
‘a\w*c’中a匹配到’aageacwgewcaw’中第一个字符a\w进行下一个字符匹配
因为\w是贪婪匹配,会一直匹配到’aageacwgewcaw’中最后一个字符wc进行下一个字符匹配时
‘a\w*c’中c发现没有可以匹配的于是\w匹配进行第一次回溯,匹配到倒数第二个字符a
‘a\w*c’中c发现还是没有可以匹配的于是\w匹配进行第二次回溯,匹配到倒数第三个字符c
‘a\w*c’中c匹配成功匹配结束返回结果

现在,如果我们将pattern改为pattern=’/a\w*?c/i’;又会回溯多少次呢?正确答案是回溯四次。

 

固态分组

固态分组,目的就是减少回溯次数, 使用(?>…)括号中的匹配时如果产生了备选状态,那么一旦离开括号便会被立即 引擎抛弃掉。举个典型的例子如: ‘\w+:’这个表达式在进行匹配时的流程是这样的,会优先去匹配所有的符合\w的字符,假如字符串的末尾没有’:’,即匹配没有找到冒号,此时触发回溯机制,他会迫使前面的\w+释放字符,并且在交还的字符中重新尝试与’:’作比对。但是问题出现在这里: \w是不包含冒号的,显然无论如何都不会匹配成功,可是依照回溯机制,引擎还是得硬着头皮往前找,这就是对资源的浪费。所以我们就需要避免这种回溯,对此的方法就是将前面匹配到的内容固化,不令其存储备用状态!,那么引擎就会因为没有备用状态可用而只得结束匹配过程。大大减少回溯的次数。 

如下代码,就不会进行回溯:

$str='nihaoaheloo';
$pattern='/(?>\w+):/';
$rs=preg_match($pattern, $str);

当然有的时候,又需慎用固态分组,如下,我要检查$str中是否包含以a结尾的字符串,很明显是包含的,但是因为使用了固态分组,反而达不到我们想要的效果

$str='nihaoahelaa';
$pattern1='/(?>\w+)a/';
$pattern2='/\w+a/';
$rs=preg_match($pattern1, $str);//0
$rs=preg_match($pattern2, $str);//1

 

6.php中正则的优缺点


php中正则在某些时候,能帮我们解决php函数很多困难的匹配或是替换。然后php中正则的效率,往往是我们需要考虑的,所以在某些时候,能不用正则还是尽量不去用它,除非,某些场合必须用到,或是我们能够有效减少其回溯次数。


【PHP常见的正则表达式一览(参考文章):https://ittxx.cn/view/103  】


转载请注明: ITTXX.CN--分享互联网 » php基础(九)--正则表达式、应用和实例汇总详解

最后更新:2020-11-19 09:46:32

赞 (6) or 分享 ()
游客 发表我的评论   换个身份
取消评论

表情
(1)个小伙伴在吐槽
  1. 666
    游客2020-11-19 09:46 (1个月前) 回复