正则表达式
1.初始正则
1.1正则表达式
正则表达式作为一个匹配的模版,是由原子(普通字符,例如字符a到z)、特殊字符(元字符,例如*、+和?等)、以及模式修正符三部分组成的文字模式
在php中有两套正则表达式,一套叫PCRE—(Perl Compatible Regular Expression)库提供的。使用“preg_”为前缀命名的函数;
PCRE的来源与perl语言,这是对字符串处理比较强大的语言,起初php就是由perl开发的产品。
另外一套叫PCIX (Portable Operating System Interface of Unix )扩展提供的。使用以“ereg_”为前缀命名的函数;
1.2几个fp
- 若干个正则匹配的函数: preg_match()
- 进行正则表达式匹配 preg_match_all
- 进行全局正则表达式匹配 preg_replace
- 执行正则表达式的匹配和替换
- preg_split() 正则分割字符串
- preg_grep 返回与模式匹配的数组单元
- preg_replace_callback 用回调函数执行正则表达式的搜索和替换
2正则的语法
2.1定界符 在程序语言中都使用与perl兼容的正则表达式,通常需要将模式表达式放在定界符之间,如:"/"
作为定界符经常使用斜线/,如“/apple/”。用户只要把需要匹配的模式内容定界符中即可,当然作为字符的定界符也不局限于 “/”。除了字母,数字和斜线‘/’以外的任何字符都可以作为定界符像"# ! | "
在程序语言中都使用与perl兼容的正则表达式,通常需要将模式表达式放在定界符之间,如:"/"
作为定界符经常使用斜线/,如“/apple/”。用户只要把需要匹配的模式内容定界符中即可,当然作为字符的定界符也不局限于 “/”。除了字母,数字和斜线‘/’以外的任何字符都可以作为定界符像"# ! | "
fp:
/</\w+> —使用反斜线作为定界符合法
|(\d{3})-\d+|S ----使用竖线作为定界符合法
!^(?i)php[34]! --使用竖线”!”作为定界符合法
{^\s+(\s+)?$} --使用竖线”}”作为定界符合法
/href=‘(.*)’ --非法定界符,缺少结束定界符
1-\d3-\d3-\d4| --非法定界符,缺少其实定界符
2.2原子
原子是正则表达式的最基本的组成单元,而且在每个模式中最少要少包含一个原子。原子是由所有那些未显示指定为元字符的打印和非打印字符组成,具体分为5类。
- 普通字符作为原子: 如 az、AZ、0~9 等
- 一些特殊字符和转义后元字符作为原子:所有标点符号,但语句特殊意义的符号需要转义后才可作为原子,如:\” \’ * + ? . 等
- 一些非打印字符作为原子: 如:\f \n \r \t \v \cx4. 使用“通用字符类型”作为原子:如:\d \D \w \W \s \S。
- 自定义原子表([])作为原子:如:’/[apj]sp/’ ’/[^apj]sp/’
fp:
\cx
匹配由于x指明的控制字符。如\cx 匹配一个control-m或者回车符号。x的值必须是A-Z 或者 a-z之间。
\f
匹配一个换页符。等价于\x0c或者\cL
\n
匹配一个换行符等价于\x0a 或者\cJ
\r
匹配一个回车符,等价于\x0d或者\cM
\t
匹配一个制表符等价于\x09或者\cl
\v
匹配一个垂直制表符等价于\0xb或者\xK
\d
表示匹配一个任意的十进制数字{0-9}
\D
匹配一个非十进制数字{^0-9
\s
匹配一个任意的空白符,等价于{\f\n\r\t\v}
\S
匹配匹配除空白字符以外的字符{^\f\n\r\t\v}
\w
匹配一个任意数字,字母或者下划线{0-9a-zA-Z}
\W
匹配一个除数字字母下划线的任意字符,等价于{^0-9a-zA- Z}
2.3原字符 *
匹配0,1次多次前面的原子
+
匹配1次或多次其前面的原子
?
匹配0次或多次其前面的原子
.
匹配除换行以外任意一个字符
|
匹配两个或多个分支选择
{n}
表示前面的原子出现n次
{n,}
表示其前面的原子不小于n次
{n,m}
表示前面的原子至少出现n次最多出现m次
^或者\A
匹配字符串开始的位置,或者多行模式下,行的开头。
$或者\Z
匹配输入字符串的结束位置,或者多行模式下,行的结尾.
\b
匹配单词的边界
\B
匹配单词边界以外的部分
[]
匹配括号中任意一个原子
[^]
匹配除方括号中的原子以外任意一个字符
()
匹配其整体为一个原子,即模式单元。可以理解为由多个单个原子组成的大原子
*
匹配0,1次多次前面的原子
+
匹配1次或多次其前面的原子
?
匹配0次或多次其前面的原子
.
匹配除换行以外任意一个字符
|
匹配两个或多个分支选择
{n}
表示前面的原子出现n次
{n,}
表示其前面的原子不小于n次
{n,m}
表示前面的原子至少出现n次最多出现m次
^或者\A
匹配字符串开始的位置,或者多行模式下,行的开头。
$或者\Z
匹配输入字符串的结束位置,或者多行模式下,行的结尾.
\b
匹配单词的边界
\B
匹配单词边界以外的部分
[]
匹配括号中任意一个原子
[^]
匹配除方括号中的原子以外任意一个字符
()
匹配其整体为一个原子,即模式单元。可以理解为由多个单个原子组成的大原子
2.4需要注意的几点
字符串边界限制
在某些情况下,需要对匹配范围进行限定,以获得更准确的匹配结果。“^”和“KaTeX parse error: Undefined control sequence: \A at position 104: …me in”中元字符“^”或“\̲A̲” 置于字符串的开始确保模式匹…”或“\Z” 置于字符串的结束,确保模式匹配出现字符串尾端。/in / 如 果 不 加 边 界 限 制 元 字 符 , 将 获 得 更 多 的 匹 配 结 果 。 / T o m /如果不加边界限制元字符,将获得更多的匹配结果。/^Tom /如果不加边界限制元字符,将获得更多的匹配结果。/Tom/精确匹配 /Tom/模糊匹配
单词边界限制
在使用各种编辑软件的查找功能时,可以通过选择“按单词查找”获得更准确的结果。正则表达式中也提供类似的功能。例如:在字符串“This island is a beautiful land”中元字符“\b”对单词的边界进行匹配;/\bis\b/ 匹配单词“is”,不匹配“This”和“island”。/\bis 匹配单词“is”和“island”中的“is”,不匹配“This”元字符“\B”对除单词边界以外的部分进行匹配。/\Bis\B/ 将明确的指示不与单词的左、右边界匹配,只匹配单词的内部。所以在这个例子中没有结果。/\Bis 匹配单词“This”中的“is”
重复匹配
正则表达式中有一些用于重复匹配某些原子的元字符:“?”、“”、“+”。他们主要的区别是重复匹配的次数不同。元字符“?”:表示0次或1次匹配紧接在其前的原子。例如:/colou?r/匹配“colour”或“color”。元字符“”:表示0次、1次或多次匹配紧接在其前的原子。例如:/zo*/可以匹配z、zoo元字符“+”:表示1次或多次匹配紧接在其前的原子。例如:/go+gle/匹配“gogle”、“google”或“gooogle”等中间含有多个o的字符串。
fp:
元字符“{ }”准确地指定原子重复的次数,
指定所匹配的原子出现的次数。“{m}”
表示其前原子恰好出现m次。“{m,n}”表示其前原子至少出现m次,至多出现n次。“{m,}” 表示其前原子出现不
少于m次。例如:/zo{1,3}m/ 只能匹配
字符串“zom”、“zoom”、或“zooom”。/zo{3}m/ 只能匹配字符串“zooom”。/zo{3,}m/ 可以匹配以
“z” 开头,“m”结束,中间至少为3
个“o”的字符串。/bo{0,1}u/ 可以
匹配字符串“bought a butter”
中的“bou”和“bu”,等价于bo?u。
任何一个字符
元字符“.”匹配除换行符外任何一个字符。相当于:^\n或^\r\n。例如:/pr.y/可以匹配的字符串“prey”、“pray”或“pr%y”等。通常可以使用“.*”组合来匹配除换行符外的任何字符。在一些书籍中也称其为“全匹配符” 或 “单含匹配符”。例如:/^a.*z / 表 示 可 以 匹 配 字 母 “ a ” 开 头 , 字 母 “ z ” 结 束 的 任 意 不 包 括 换 行 符 的 字 符 串 。 / . + / 也 可 以 完 成 类 似 的 匹 配 功 能 所 不 同 的 是 其 至 少 匹 配 一 个 字 符 。 / a . + z /表示可以匹配字母“a”开头,字母“z”结束的任意不包括换行符的字符串。/.+/ 也可以完成类似的匹配功能所不同的是其至少匹配一个字符。/^a.+z /表示可以匹配字母“a”开头,字母“z”结束的任意不包括换行符的字符串。/.+/也可以完成类似的匹配功能所不同的是其至少匹配一个字符。/a.+z/ 匹配“a%z”不匹配字符串“az”。
原子表
原子表”[]”中存放一组原子,彼此地位平等,且仅匹配其中的一个原子。如果想匹配一个 ”a” 或 ”e” 使用 [ae]。例如: Pr[ae]y 匹配 ”Pray” 或者 ”Prey ”。原子表 ”[^]” 或者称为排除原子表,匹配除表内原子外的任意一个字符。例如:/p[^u]/匹配“part”中的“pa”,但无法匹配“computer”中的“pu”因为“u”在匹配中被排除。原子表“[-]”用于连接一组按ASCII码顺序排列的原子,简化书写。例如:/x[0123456789]/可以写成x[0-9],用来匹配一个由 “x” 字母与一个数字组成的字符串。例如:/[a-zA-Z]/匹配所有大小写字母/1[0-9]$/匹配比如“z2”、 “t6” 、“g7”/0[xX][0-9a-fA-F]/匹配一个简单的十六进制数字,如“0x9”。/[^0-9a-zA-Z_]/匹配除英文字母、数字和下划线以外任何一个字符,其等价于\W。/0?[ xX][0-9a-fA-F]+/匹配十六进制数字,可以匹配“0x9B3C”或者“X800”等。/<[A-Za-z][A-Za-z0-9]*>/可以匹配“
”、“”或“”等HTML标签,并且不严格的控制大小写。
模式选择符
元字符“|”又称模式选择符。在正则表达式中匹配两个或更多的选择之一。例如:在字符串“There are many apples and pears.”中, /apple|pear/在第一次运行时匹配“apple”;再次运行时匹配“ pear”。也可以继续增加选项,如: /apple|pear|banana|lemon/
模式单元
元字符“()”将其中的正则表达式变为原子(或称模式单元)使用。与数学表达式中的括号类似,“()”可以做一个单元被单独使用。例如:/(Dog)+/匹配的“Dog”、“DogDog”、“DogDogDog”,因为紧接着“+”前的原子是元字符“()”括起来的字符串“Dog”。/You (very )+ old/匹配“You very old”、“You very very old”/Hello (world|earth)/匹配“Hello world”、“Hello earth”一个模式单元中的表达式将被优先匹配或运算。
重新使用的模式单元
系统自动将模式单元“()”中的匹配依次存储起来,在需要时可以用“\1”、“\2”、“\3”的形式进行引用。当正则表达式包含有相同的模式单元时,这种方法非常便于对其进行管理。注意使用时需要写成“\1”、“\2”例如:/^\d{2}([\W])\d{2}\1\d{4}$/匹配“12-31-2006”、“09/27/1996”、“86 01 4321”等字符串。但上述正则表达式不匹配“12/34-5678”的格式。这是因为模式“[\W]”的结果“/”已经被存储。下个位置“\1”引用时,其匹配模式也是字符“/”。当不需要存储匹配结果时使用非存储模式单元“(?:)”例如/(?:a|b|c)(D|E|F)\1g/ 将匹配“aEEg”。在一些正则表达式中,使用非存储模式单元是必要的。否则,需要改变其后引用的顺序。上例还可以写成/(a|b|c)(C|E|F)\2g/。
优先级和修正符号:
略略略。。
3字符串的匹配和查找函数
3.1.1 preg_match() --执行一个正则匹配
$pattern = '/(https?|ftps?):\/\/(www)\.([^\.\/]+)\.(com|net|org)(\/[\w-\.\/\?\%\&\=]*)?/i';
//被搜索字符串
$subject = "网址为http://www.lampbrother.net/index.php的位置是LAMP兄弟连";
//使用preg_match()函数进行匹配
if(preg_match($pattern, $subject, $matches)) {
echo "搜索到的URL为:".$matches[0]."<br>"; //数组中第一个元素保存全部匹配结果
echo "URL中的协议为:".$matches[1]."<br>"; //数组中第二个元素保存第一个子表达式
echo "URL中的主机为:".$matches[2]."<br>"; //数组中第三个元素保存第二个子表达式
echo "URL中的域名为:".$matches[3]."<br>"; //数组中第四个元素保存第三个子表达式
echo "URL中的顶域为:".$matches[4]."<br>"; //数组中第五个元素保存第四个子表达式
echo "URL中的文件为:".$matches[5]."<br>"; //数组中第六个元素保存第五个子表达式
} else {
echo "搜索失败!"; //如果和正则表达式没有匹配成功则输出
}
fp2:
$pattern = '/(https?|ftps?):\/\/(www|bbs)\.([^\.\/]+)\.(com|net|org)(\/[\w-\.\/\?\%\&\=]*)?/i';
$subject = "网址为http://bbs.lampbrother.net/index.php的位置是LAMP兄弟连,
网址为http://www.baidu.com/index.php的位置是百度,
网址为http://www.google.com/index.php的位置是谷歌。";
$i = 1; //定义一个计数器,用来统计搜索到的结果数
//搜索全部的结果
if(preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) {
foreach($matches as $urls) { //循环遍历二维数组$matches
echo "搜索到第".$i."个URL为:".$urls[0]."<br>";
echo "第".$i."个URL中的协议为:".$urls[1]."<br>";
echo "第".$i."个URL中的主机为:".$urls[2]."<br>";
echo "第".$i."个URL中的域名为:".$urls[3]."<br>";
echo "第".$i."个URL中的顶域为:".$urls[4]."<br>";
echo "第".$i."个URL中的文件为:".$urls[5]."<br>";
$i++; //计数器累加
}
} else {
echo "搜索失败!";
}
running:
preg_grep
$array = array("Linux RedHat9.0", "Apache2.2.9", "MySQL5.0.51", "PHP5.2.6", "LAMP", "100");
//返回数组中以字母开始和以数字结束,并且没有空格的单元,赋给变量$version
$version = preg_grep("/^[a-zA-Z]+(\d|\.)+$/", $array);
print_r($version);
//输出:Array ( [1] => Apache2.2.9 [2] => MySQL5.0.51 [3] => PHP5.2.6 )
running:
strstr()
echo strstr("this is a test!", "test"); //输出test!
echo strstr("this is a test!", 115); //搜索 "s" 的ASCII值所代表的字符输出s is a test!
running:
substr
/**
用于获取URL中的文件名部分
@param string $url 任何一个URL格式的字符串
@return string URL中的文件名称部分
*/
function getFileName($url) {
//获取URL字符串中最后一个“/”出现的位置,再加1则为文件名开始的位置
$location = strrpos($url, "/")+1;
//获取在URL中从$location位置取到结尾的子字符串
$fileName = substr($url, $location);
//返回获取到的文件名称
return $fileName;
}
//获取网页文件名index.php
echo getFileName("http://bbs.lampbrother.net/index.php");
//获取网页中图片名logo.gif
echo getFileName("http://bbs.lampbrother.com/images/Sharp/logo.gif");
//获取本地中的文件名php.ini
echo getFileName("file:///C:/WINDOWS/php.ini");
running:
3.2字符替换函数
preg_replace 执行一个正则的搜索和替换
mixed preg_replace ( mixed $pattern , mixed $replacement,mixed $subject [,int $limit = -1])搜索subject中匹配pattern的部分, 以replacement进行替换.
fp:
//可以匹配所有HTML标记的开始和结束的正则表达式
$pattern = "/<[\/\!]*?[^<>]*?>/is";
//声明一个带有多个HTML标记的文本
$text = "这个文本中有<b>粗体</b>和<u>带有下画线</u>以及<i>斜体</i>
还有<font color='red' size='7'>带有颜色和字体大小</font>的标记";
//将所有HTML标记替换为空,即删除所有HTML标记
echo preg_replace($pattern, "", $text);
//通过第四个参数传入数字2,替换前两个HTML标记
echo preg_replace($pattern, "", $text, 2);
running:
fp2:
$pattern = "/(\d{2})\/(\d{2})\/(\d{4})/"; //日期格式的正则表达式
$text="今年国庆节放假日期为10/01/2012到10/07/2012共7天。"; //带有两个日期格式的字串
echo preg_replace($pattern, "\\3-\\1-\\2", $text); //将日期替换为以“-”分隔的格式
echo preg_replace($pattern, "\${3}-\${1}-\${2}",$text); //将“\\1”改为“\${1}”的形式
running:
fp3:
//可以匹配所有HTML标记的开始和结束的正则表达式
$pattern = "/(<\/?)(\w+)([^>]*>)/e";//声明一个带有多个HTML标记的文本
$text = "这个文本中有<b>粗体</b>和<u>带有下画线</u>以及<i>斜体</i>还有<font color='red' size='7'>带有颜色和字体大小</font>的标记";//将所有HTML的小写标记替换为大写
echo preg_replace($pattern, "'\\1'.strtoupper('\\2').'\\3'", $text);
running:
str_replace
mixed str_replace ( mixed $search , mixed $replace , mixed KaTeX parse error: Expected 'EOF', got '&' at position 16: subject [, int &̲count ] )该函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换之后的结果。通过$count参数指定来获取替换的次数mixed str_replace ( mixed $search , mixed $replace , mixed KaTeX parse error: Expected 'EOF', got '&' at position 16: subject [, int &̲count ] )该函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换之后的结果。通过$count参数指定来获取替换的次数
fp:
$str="LAMP是目前最流行的WEB开发平台;<br>
LAMP为B/S架构软件开发的黄金组合;<br>
LAMP每个成员都是开源软件;<br>
lampBrother是LAMP的技术社区。<br>";
//区分大小写的将“LAMP”替换为“Linux+Apache+MySQL+PHP”,并统计替换次数
echo str_replace("LAMP", "Linux+Apache+MySQL+PHP",$str, $count);
echo "区分大小写时共替换".$count."次<br>"; //替换4次
//不区分大小写的将“LAMP”替换为“Linux+Apache+MySQL+PHP”,并统计替换次数
echo str_ireplace("LAMP", "Linux+Apache+MySQL+PHP", $str,$count);
echo "不区分大小写时共替换".$count."次<br>"; //替换5次
running:
a-z ↩︎