Aug 5

php学习笔记之 正则表达式 不指定

felix021 @ 2008-8-5 00:20 [IT » 网络] 评论(2) , 引用(0) , 阅读(7783) | Via 本站原创 | |
php学习笔记之 正则表达式

正则表达式Regular Expression,查找和替换字符串模式的简洁、灵活、强大的表示法。
在PHP中正则表达式的表示分为两种,分别是POSIX和PCRE两种规格。

--------------

1. POSIX正则表达式
POSIX = Portable Operating System Implementation for uniX.


(1)定位符:定位符不匹配字符串中的任何一个字符,只匹配位置。
^:匹配行首,表示接下来的字符必须从行首开始才能匹配
$:匹配行末,表示之前的字符必须正好达到行末才能匹配
e.g.
"^once"匹配"once again", 不匹配"abc once"
"yes$"匹配"Oh, yes", 不匹配"yesterday"
"^hi$"只匹配"hi", 不匹配其他字符串


(2)POSIX量词:指定模式中量词前的子表达式必须出现多少次才能满足匹配
{n}: 匹配正好n次, 如"fo{3}"匹配"foooooo"中的"fooo"
{n,}: 匹配至少n次,如"fo{3,}"匹配"fooooo"中的"fooooo"(默认贪婪匹配,匹配到最长)
{n,m}: 匹配至少n次之多m次,如"fo{1,3}"匹配"fooooo"中的"fooo"(默认贪婪匹配)
*: 匹配0次或多次,相当于{0,},如"fo*"匹配"fooooo"中的"fooooo"(贪婪匹配)
+: 匹配至少1次,相当于{1,},如"fo+"匹配"fooooo"中的"fooooo"(贪婪匹配)
?: 匹配0次或1次,相当于{0,1},如"do(es)?"匹配"does"中的"does"(贪婪匹配)
注意:如果不希望贪婪匹配,可以在限定词后添加一个?来实现最小匹配
e.g.
"fo+?"匹配"fooooo"中的"fo", 只匹配了一个o


(3)方括号表达式:匹配括号中指定要求的任何一个字符(仅1个字符)
如果^被用于方括号表达式中,表示排除其后的那个字符
如果要加入特殊字符,使用\转义,如\. \+ \[ \-
e.g.
[a-z]匹配a~z的任意一个字符
[a-zA-Z0-9]匹配任意字母或数字
[^0]匹配0之外的任何字符
[\.\+\-\[\]\\\^\$]匹配.+-[]\^$中的任意一个字符


(4)特殊字符.
.可以用来匹配除了空串和换行之外的任意一个字符


(5)预定义字符串
[[:alpha:]] 所有字母, 等同于[A-Za-z]
[[:digit:]] 所有数字,等同于[0-9]
[[:alnum:]] 所有字母和数字,等同于[a-zA-Z0-9]
[[:ctrl:]]  控制字符, 包括TAB退格或者\反斜线
[[:space:]] 空白字符,包括空格 TAB 换行 换页和回车
[[:punct:]] 标点符号,包括键盘上所有上档字符,如! @ #等
[[:xdigit:]]十六进制字符,相当于[a-fA-F0-9]
[[:graph:]] 等同于alpha + xdigit + punct


(6)POSIX子模式(sub pattern)
子模式是用小括号把几个正则表达式组合在一次,作为一个独立的单元对待
如(dog|cat)可以匹配"dog"也可以匹配"cat"


(7)POSIX正则表达式函数
--
bool ereg ( string pattern, string string [, array regs] )
以区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。
如果在 string 中找到 pattern 模式的匹配则返回 TRUE,如果没有找到匹配或出错则返回 FALSE。
  //如果找到与 pattern 中圆括号内的子模式相匹配的子串并且函数调用给出了第三个参数 regs,
  //则匹配项将被存入 regs 数组中。$regs[1] 包含第一个左圆括号开始的子串,
  //$regs[2] 包含第二个子串,以此类推。$regs[0] 包含整个匹配的字符串。
e.g.
以下代码可以简单判断一个邮箱地址是否正确
<?php
if(ereg("^([a-zA-Z0-9\_\.\-]+)@(([a-zA-Z0-9\-\_].)+([a-zA-Z0-9]+))$", $email)){
    echo "legal";
}else{
    echo "illegal";
}
?>

--
bool eregi ( string pattern, string string [, array regs] )
忽略大小写版本的ereg()函数。
--
string ereg_replace ( string pattern, string replacement, string string )
本函数在 string 中扫描与 pattern 匹配的部分,并将其替换为 replacement。
返回替换后的字符串。(如果没有可供替换的匹配项则会返回原字符串。)
如果 pattern 包含有括号内的子串,则 replacement 可以包含形如 \\digit 的子串,这些子串将被替换为数字表示的的第几个括号内的子串(即逆向引用);\\0 则包含了字符串的整个内容。最多可以用九个子串。括号可以嵌套,此情形下以左圆括号来计算顺序。
如果未在 string 中找到匹配项,则 string 将原样返回。
e.g.
<?php
$str = "please visit http://www.19880711.com for more...";
$pattern = "[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]";
$replacement = "<a href=\"\\0\">\\0</a>";
echo ereg_replace($pattern, $replacement, $str);
?>

以上代码输出please visit <a href="http://www.19880711.com">http://www.19880711.com</a> for more...
--
string eregi_replace ( string pattern, string replacement, string string )
本函数和 ereg_replace() 完全相同,只除了在匹配字母字符时忽略大小写的区别。
--
array split ( string pattern, string string [, int limit] )
本函数返回一个字符串数组,每个单元为 string 经区分大小写的正则表达式 pattern 作为边界分割出的子串。如果设定了 limit,则返回的数组最多包含 limit 个单元,而其中最后一个单元包含了 string 中剩余的所有部分。如果出错,则 split() 返回 FALSE。
e.g.
<?php
$arr = split("( |\||\-)", "张三 15-男|未婚");
var_dump($arr);
?>

以上代码把该字符串以空格( )横杆(-)竖线(|)为分隔符分割后存入数组$arr
输出为
array(4) { [0]=>  string(6) "张三" [1]=>  string(2) "15" [2]=>  string(3) "男" [3]=>  string(6) "未婚" }
--
spliti()
本函数和 split() 相同,只除了在匹配字母字符时忽略大小写的区别。
--
string sql_regcase ( string string )
返回与 string 相匹配的正则表达式,不论大小写字母。返回的表达式是将 string 中的每个字母字符转换为方括号表达式,该方括号表达式包含了该字母的大小写形式。其它字符保留不变。
e.g.
<?php
echo sql_regcase ("Foo - bar.");
?>

输出为[Ff][Oo][Oo] - [Bb][Aa][Rr].



--------

2. PCRE正则表达式
PCRE = Perl Compatible Regular Expression, Perl兼容正则表达式(Perl是字符串处理功能最强大的语言之一,PHP最初就是由Perl开发的)


(1)PCRE模式的格式
PCRE模式和POSIX模式不同,在模式的两端分别要加上分隔符(最常用的是斜线/),且在结束的分隔符后面可以跟上修饰符,用于更改正则表达式的行为(比如是否大小写敏感等).
e.g
模式 '/^this is a pattern$/i' 大小写不敏感地匹配字符串。


(2)PCRE元字符
注意,前面的双斜杆是将斜杆(\)在填入模式串时转义,即需要写成"/\\b/"这样的形式
--
通用字符类型(匹配字符)
\\d     任一十进制数字
\\D     任一非十进制数的字符
\\s     匹配任意空白,如TAB 空格
\\S     任一非空白字符
\\w     任一“字”的字符 “字”的字符是指任何一个字母或数字或下划线
\\W     任一“非字”的字符
--
断言(匹配位置)
\\A     只匹配字符串开头(独立于多行模式)
\\Z     目标的结尾或位于结尾的换行符前(独立于多行模式)
\\z     目标的结尾(独立于多行模式)
\\b     词边界,查找词的开始和结尾
\\B     非词分界线
\\G     目标中的第一个匹配位置
--
圆点(.)   匹配除换行外的任意字符(若设定了s修正选项则也匹配换行符)
音调符^   匹配字符串的开始位置,若在方括号的第一个位置则表示"排除"其后的所有字符
美元符     匹配字符串的结尾
大括号     量词,{n}匹配正好n次,{n,}匹配至少n次,{n,m}匹配至少n次之多m次
星号(*)   匹配0次或多次,相当于{0,}
加号(+)   匹配至少1次,相当于{1,}
问号(?)   匹配0次或1次,相当于{0,1}
方括号[]  指定字符类,如[aeiou]匹配任何一个元音字母
            若^紧跟在[之后表示非括号内字符的字符,如[^aeiou]匹配任意一个非元音字母的字符
            横杆(-)指定一个范围,如[a-z]匹配任意一个字母。范围是以 ASCII 比较顺序来操作的。
圆括号()  定义子模式
竖线(|)   竖线字符用来分隔多选一模式。例如子模式(dog|cat)匹配dog或cat
的使用和POSIX正则表达式相同.
--
e.g.
模式 '/\\b(\\w+?)\\b/i' 大小写不敏感地匹配连续出现的仅包含英文和数字的串


(3)PCRE匹配修饰符
i   如果设定此修正符,模式中的字符将同时匹配大小写字母。
m   当设定了此修正符,^和$除了匹配整个字符串开头和结束外,还分别匹配其中的换行符的之后和之前。
s   如果设定了此修正符,模式中的圆点元字符(.)匹配所有的字符,包括换行符。
x   从模式中删除空白符和注释
D   如果设定了此修正符,模式中的美元元字符仅匹配目标字符串的结尾。
     没有此选项时,如果最后一个字符是换行符的话,美元符号也会匹配此字符之前
S   当一个模式将被使用若干次时,为加速匹配起见,如果设定了此修正符则会先对其进行分析。
U   启用非贪婪匹配。也可以通过在模式之中设定 (?U) 修正符或者在数量符后跟一个?(如 .*?)来启用此选项。
u   模式字符串被当成 UTF-8
e.g.
模式 '/\\b(\\w+)\\b/iU' 大小写不敏感地匹配连续出现的仅包含英文和数字的串
e.g.
<?php
$str = '"Hi", he said, "nice to meet you!"';
$pattern = "/\"(.+)\"/iU";
$replacement = "\\1#\\2\n";
preg_match_all($pattern, $str, $matches);
var_dump($matches);
?>

输出为(匹配了两个字符串)
array(2) { [0]=>  array(1) { [0]=>  string(34) ""Hi", he said, "nice to meet you!"" } [1]=>  array(1) { [0]=>  string(32) "Hi", he said, "nice to meet you!" } }
如果在$pattern后面没有加上修正符U,那么仅会匹配一个从开始到结尾一整个字符串(贪婪匹配)


(4)PCRE正则表达式函数
--
int preg_match ( string pattern, string subject [, array matches ] )
在 subject 字符串中搜索与 pattern 给出的正则表达式相匹配的内容。
如果提供了 matches,则其会被搜索的结果所填充。$matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。
e.g.
<?php
if(preg_match("/php/i", "PHP is very powerful")){
    echo "TRUE";
}else{
    echo "FALSE";
}
?>

以上代码输出TRUE(模式"/php/i"匹配大小写忽略的字符串"php")
--
array preg_grep ( string pattern, array input )
preg_grep() 返回一个数组,其中包括了 input 数组中与给定的 pattern 模式相匹配的单元。
e.g.
<?php
$arr = array("php", "PHP", "pxp", "pcp", "Php");
var_dump(preg_grep("/php/i", $arr));
?>

上例过滤了不包含"php"(大小写忽略)的数组项,输出
array(3) {
  [0]=>
  string(3) "php"
  [1]=>
  string(3) "PHP"
  [4]=>
  string(3) "Php"
}

--
int preg_match_all ( string pattern, string subject, array matches [, int flags] )
函数会在 subject 中搜索所有与 pattern 给出的正则表达式匹配的内容并将结果以 flags 指定的顺序放到 matches 中。搜索到第一个匹配项之后,接下来的搜索从上一个匹配项末尾开始。flags可以是下列标记的组合(注意把 PREG_PATTERN_ORDER 和 PREG_SET_ORDER 合起来用没有意义):
    PREG_PATTERN_ORDER
    PREG_SET_ORDER
    PREG_OFFSET_CAPTURE
如果没有给出标记,则假定为 PREG_PATTERN_ORDER。 返回整个模式匹配的次数(可能为零),如果出错返回 FALSE。
e.g.
<?php
$str = '<b>a</b><b>b</b><b>c</b>';
$pattern = "/<b>(.+)<\/b>/iU";
echo preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER), "\n";
var_dump( $matches );
?>

输出结果为
3
array(2) {
  [0]=>
  array(3) {
    [0]=>
    string(8) "<b>a</b>"
    [1]=>
    string(8) "<b>b</b>"
    [2]=>
    string(8) "<b>c</b>"
  }
  [1]=>
  array(3) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
    [2]=>
    string(1) "c"
  }
}
对于另外两个flags的值的作用,用此例进行测试即可看出区别。
--
string preg_quote ( string str [, string delimiter] )
preg_quote() 以 str 为参数并给其中每个属于正则表达式语法的字符前面加上一个反斜线。如果你需要以动态生成的字符串作为模式去匹配则可以用此函数转义其中可能包含的特殊字符。
如果提供了可选参数 delimiter,该字符也将被转义。可以用来转义 PCRE 函数所需要的定界符,最常用的定界符是斜线 /。
正则表达式的特殊字符包括:. \\ + * ? [ ^ ] $ ( ) { } = ! < > | :
e.g.
<?php
$pattern = "/<b>(.+)<\/b>/iU";
echo preg_quote($pattern);
?>

输出为 /\<b\>\(\.\+\)\<\\/b\>/iU
--
mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit] )
在 subject 中搜索 pattern 模式的匹配项并替换为 replacement。如果指定了 limit,则仅替换 limit 个匹配,如果省略 limit 或者其值为 -1,则所有的匹配项都会被替换。
pattern和replacement可以是字符串,也可以是一个字符串数组。
replacement 可以包含 \\n 形式(POSIX格式的逆向引用)或(自 PHP 4.0.4 起)$n 形式的逆向引用,首选使用后者。每个此种引用将被替换为与第 n 个被捕获的括号内的子模式所匹配的文本。n 可以从 0 到 99,其中 \\0 或 $0 指的是被整个模式所匹配的文本。对左圆括号从左到右计数(从 1 开始)以取得子模式的数目。
对替换模式在一个逆向引用后面紧接着一个数字时(即:紧接在一个匹配的模式后面的数字),不能使用熟悉的 \\1 符号来表示逆向引用。举例说 \\11,将会使 preg_replace() 搞不清楚是想要一个 \\1 的逆向引用后面跟着一个数字 1 还是一个 \\11 的逆向引用。本例中的解决方法是使用 \${1}1。这会形成一个隔离的 $1 逆向引用,而使另一个 1 只是单纯的文字。
【注意】特别对于$的问题:因为在双引号("")中包含的美元符号($)会被php解释为一个变量的开始(比如"$var1")并将该变量的值替换进去,所以最好使用单引号来包含逆向引用('$1'),或者在双引号包含的字符串里面,在表示逆向引用时,一定要在美元符号前面加上一个反斜杆("\${1}")进行转义。
e.g.
以下代码实现论坛UBB代码中的[b][/b]标签到<b></b>标签的替换:
<?php
$str = '[b]test[/b][b]test2[/b]';
$pattern = "/\[b\](.+)\[\/b\]/iU";
$replacement = "<b>\${1}</b>";
echo preg_replace($pattern, $replacement, $str);
?>

输出为<b>test</b><b>test2</b>

以下代码实现UBB中的多个标签(b, i, u img, url)到相应html标签的替换:
<?php

$pattern = array(

'/\[b\](.*?)\[\/b\]/is',

'/\[i\](.*?)\[\/i\]/is',

'/\[u\](.*?)\[\/u\]/is',

'/\[img\=(.*?)\]/is',

'/\[url\=(.*?)\](.*?)\[\/url\]/is'

);

$replace = array(

"<b>\${1}</b>",

"<i>\${1}</i>",

"<u>\${1}</u>",

"<img src=\"\${1}\">",

"<a href=\"\${1}\">\${2}</a>"

);

$str = "[b]Welome to [/b][url=http://www.19880711.com][i]felix's blog[/i][/url]\n";

$str1 = htmlentities($str);

$str1 = preg_replace($pattern, $replace, $str1);

echo nl2br($str1);

?>

输出为<b>Welome to </b><a href="http://www.19880711.com"><i>felix's blog</i></a><br />
--
mixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit] )
本函数的行为几乎和 preg_replace() 一样,除了不是提供一个 replacement 参数,而是指定一个 callback 函数。该函数将以目标字符串中的匹配数组作为输入参数,并返回用于替换的字符串。
e.g.(取自php_manual的示例)
<?php
  /* 一个 UNIX 风格的命令行过滤器,将每个段落开头的
   * 大写字母转换成小写字母 */

  $fp = fopen("1.txt", "r") or die("can't open 1.txt");
  while (!feof($fp)) {
      $line = fgets($fp);
      $line = preg_replace_callback(
          '|<p>\s*\w|',
          create_function(
              // 这里使用单引号很关键,
              // 否则就把所有的 $ 换成 \$
              '$matches', /*匿名函数的参数*/
              'return strtolower($matches[0]);' /*匿名函数的函数体*/
          ),
          $line
      );
      echo $line;
  }
  fclose($fp);
?>

--
array preg_split ( string pattern, string subject [, int limit ] )
返回一个数组,包含 subject 中沿着与 pattern 匹配的边界所分割的子串。
如果指定了 limit,则最多返回 limit 个子串,如果 limit 是 -1,则意味着没有限制,可以用来继续指定可选参数 flags。
e.g.
<?php
// split the phrase by any number of commas or space characters,
// which include " ", \r, \t, \n and \f
$keywords = preg_split ("/[\s,]+/", "hypertext language, programming");
?>



---------
至此正则表达式的内容就算告一段落了,这个学习笔记写得真久阿,都可以出一个大专题了。最后备注几点: PCRE正则表达式的函数一般比POSIX正则表达式函数来得快;如果只是简单的字符串查找替换,用系统自带的字符串函数(如str_replace, strpos等),效率更高。



欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
boluor
2009-8-11 01:17
收藏拉smile
Feli
2008-9-24 02:48
Thank you
felix021 回复于 2008-9-24 03:01
grin
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]