本节介绍php正则表达式的匹配规则
1. 基本模式匹配
一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:
^once
这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There once was a man from NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。
bucket$
这个模式与"Who kept all of this cash in a bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:
^bucket$
只匹配字符串"bucket"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式
once
与字符串
There once was a man from NewYork
Who kept all of his cash in a bucket.
是匹配的。
在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠()打头。制表符的转义序列是:t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:
^t
类似的,用n表示“新行”,r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用表示,句号.用.表示,以此类推。
2. 字符簇
在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。
所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu]
这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:
[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9.-] //匹配所有的数字,句号和减号
[ frtn] //匹配所有的白字符
同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3" 或"b52"的话,用这个模式:
^[a-z][0-9]$
尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:
^[^0-9][0-9]$
这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:
[^a-z] //除了小写字母以外的所有字符
[^/^] //除了()(/)(^)之外的所有字符
[^"'] //除了双引号(")和单引号(')之外的所有字符
特殊字符"." (点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。
PHP的正规表达式有一些内置的通用字符簇,列表如下:
字符簇含义
[[:alpha:]] 任何字母
[[:digit:]] 任何数字
[[:alnum:]] 任何字母和数字
[[:space:]] 任何白字符
[[:upper:]] 任何大写字母
[[:lower:]] 任何小写字母
[[:punct:]] 任何标点符号
[[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]
3. 确定重复出现
到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。
字符簇 含义
^[a-zA-Z_]$ 所有的字母和下划线
^[[:alpha:]]{3}$ 所有的3个字母的单词
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$ 包含多于两个a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,} 如:baad和aaa,但Nantucket不行
t{2} 两个制表符
.{2} 所有的两个字符
这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现 x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。我们可以把模式扩展到更多的单词或数字:
^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]{1,}$ //所有的正数
^-{0,1}[0-9]{1,}$ //所有的整数
^-{0,1}[0-9]{0,}.{0,1}[0-9]{0,}$ //所有的小数
最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号(-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(.{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。
特殊字符"?"与{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:
^-?[0-9]{0,}.?[0-9]{0,}$
特殊字符"*"与{0,}是相等的,它们都代表着“0个或多个前面的内容”。最后,字符"+"与 {1,}是相等的,表示“1个或多个前面的内容”,所以上面的4个例子可以写成:
^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]+$ //所有的正数
^-?[0-9]+$ //所有的整数
^-?[0-9]*.?[0-9]*$ //所有的小数
当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。
php正则表式的完全教程,全部讲完,希望您对正则表达式的理解已有所加强。
更多内容,请关注 正则表达式 栏目。
首先,让我们看看两个特别的字符:’^’和‘$’。它们分别用来匹配字符串的开始和结束。
举例说明:
"^The": 匹配以 "The"开头的字符串;
"of despair$": 匹配以 "of despair" 结尾的字符串;
"^abc$": 匹配以abc开头和以abc结尾的字符串,实际上是只有abc与之匹配;
"notice": 匹配包含notice的字符串;
你可以看见如果你没有用我们提到的两个字符(最后一个例子),就是说 模式(正则表达式) 可以出现在被检验字符串的任何地方,你没有把他锁定到两边。
这里还有几个字符 *, +,和 ?, 他们用来表示一个字符可以出现的次数或者顺序. 他们分别表示:"zero or more", "one or more", and "zero or one." 这里是一些例子:
"ab*": 匹配字符串a和0个或者更多b组成的字符串("a", "ab", "abbb", etc.);
"ab+": 和上面一样,但最少有一个b ("ab", "abbb", etc.);
"ab?":匹配0个或者一个b;
"a?b+$": 匹配以一个或者0个a再加上一个以上的b结尾的字符串.
你也可以在大括号里面限制字符出现的个数,比如
"ab{2}": 匹配一个a后面跟两个b(一个也不能少)("abb");
"ab{2,}": 最少更两个b("abb", "abbbb", etc.);
"ab{3,5}": 2-5个b("abbb", "abbbb", or "abbbbb").
你还要注意到你必须总是指定 (i.e, "{0,2}", not "{,2}").同样,你必须注意到, *, +, 和? 分别和一下三个范围标注是一样的,"{0,}", "{1,}", 和 "{0,1}"。
现在把一定数量的字符放到小括号里,比如:
"a(bc)*": 匹配 a 后面跟0个或者一个"bc";
"a(bc){1,5}": 一个到5个 "bc."
还有一个字符 │, 相当于OR 操作:
"hi│hello": 匹配含有"hi" 或者 "hello" 的 字符串;
"(b│cd)ef": 匹配含有 "bef" 或者 "cdef"的字符串;
"(a│b)*c": 匹配含有这样 - 多个(包括0个)a或b,后面跟一个c的字符串 的字符串;
一个点(.)可以代表所有的 单一字符:
"a.[0-9]": 一个a跟一个字符再跟一个数字的 (含有这样一个字符串的字符串将被匹配,以后省略此括号)
"^.{3}$": 以三个字符结尾.中括号括住的内容只匹配一个 单一的字符
"[ab]": 匹配单个的 a 或者 b ( 和 "a│b" 一样);
"[a-d]": 匹配a 到d的单个字符 (和"a│b│c│d" 还有 "[abcd]"效果一样);
"^[a-zA-Z]": 匹配以字母开头的字符串
"[0-9]%": 匹配含有 形如 x% 的字符串
",[a-zA-Z0-9]$": 匹配以逗号在加一个数字或字母结尾的字符串
你也可以把你不想要得字符列在中括号里,你只需要在总括号里面使用^ 作为开头 (i.e., "%[^a-zA-Z]%" 匹配含有 两个百分号里面有一个非字母 的字符串).
为了能够解释,但"^.[$()│*+?{"作为有特殊意义的字符的时候,你必须在这些字符面前加, 还有在php3中你应该避免在模式的最前面使用, 比如说,正则表达式 "($│?[0-9]+" 应该这样调用 ereg("($│?[0-9]+", $str) (不知道php4是不是一样)
不要忘记在中括号里面的字符是这条规路的例外—在中括号里面, 所有的特殊字符,包括(), 都将失去他们的特殊性质(i.e., "[*+?{}.]"匹配含有这些字符的字符串). 还有,正如regx的手册告诉我们: "如果列表里含有 ], 最好把它作为列表里的第一个字符(可能跟在^后面). 如果含有-, 最好把它放在最前面或者最后面, or 或者一个范围的第二个结束点(i.e. [a-d-0-9]中间的‘-’将有效.
为了完整, 我应该涉及到 collating sequences, character classes, 同埋 equivalence classes. 但我在这些方面不想讲的太详细, 这些在下面的文章仲都不需要涉及到. 你们可以在regex man pages 那里得到更多消息.
如何构建一个模式来匹配 货币数量 的输入
好了,现在我们要用我们所学的来干一些有用的事:构建一个匹配模式去检查输入的信息是否为一个表示money的数字。我们认为一个表示money的数量有四种方式: "10000.00" 和 "10,000.00",或者没有小数部分, "10000" and "10,000". 现在让我们开始构建这个匹配模式:
^[1-9][0-9]*$
这是所变量必须以非0的数字开头.但这也意味着 单一的 "0" 也不能通过测试. 以下是解决的方法:
^(0│[1-9][0-9]*)$
"只有0和不以0开头的数字与之匹配",我们也可以允许一个负号再数字之前:
^(0│-?[1-9][0-9]*)$
这就是: "0 或者 一个以0开头可能有一个负号在前面的数字." 好了, 好了现在让我们别那么严谨,允许以0开头.现在让我们放弃 负号 , 因为我们在表示钱币的时候并不需要用到. 我们现在指定 模式 用来匹配小数部分:
^[0-9]+(.[0-9]+)?$
这暗示匹配的字符串必须最少以一个阿拉伯数字开头. 但是注意,在上面模式中 "10." 是不匹配的, 只有 "10" 和 "10.2" 才可以. (你知道为什么吗)
^[0-9]+(.[0-9]{2})?$
我们上面指定小数点后面必须有两位小数.如果你认为这样太苛刻,你可以改成:
^[0-9]+(.[0-9]{1,2})?$
这将允许小数点后面有一到两个字符. 现在我们加上用来增加可读性的逗号(每隔三位), 我们可以这样表示:
^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
不要忘记加号 + 可以被乘号 * 替代如果你想允许空白字符串被输入话 (为什么?). 也不要忘记反斜杆 ’’ 在php字符串中可能会出现错误 (很普遍的错误). 现在,我们已经可以确认字符串了, 我们现在把所有逗号都去掉 str_replace()(",", "", $money) 然后在把类型看成 double然后我们就可以通过他做数学计算了.
构造检查email的正则表达式
让我们继续讨论怎么验证一个email地址. 在一个完整的email地址中有三个部分: POP3 用户名 (在 @ 左边的一切), @, 服务器名(就是剩下那部分). 用户名可以含有大小写字母阿拉伯数字,句号 (.), 减号(-), and 下划线 (_). 服务器名字也是符合这个规则,当然下划线除外.
现在, 用户名的开始和结束都不能是句点. 服务器也是这样. 还有你不能有两个连续的句点他们之间至少存在一个字符,好现在我们来看一下怎么为用户名写一个匹配模式:
^[_a-zA-Z0-9-]+$
现在还不能允许句号的存在. 我们把它加上:
^[_a-zA-Z0-9-]+(.[_a-zA-Z0-9-]+)*$
上面的意思就是说: "以至少一个规范字符(除.意外)开头,后面跟着0个或者多个以点开始的字符串."
简单化一点, 我们可以用 eregi()取代 ereg().eregi()对大小写不敏感, 我们就不需要指定两个范围 "a-z" 和 "A-Z" – 只需要指定一个就可以了:
^[_a-z0-9-]+(.[_a-z0-9-]+)*$
后面的服务器名字也是一样,但要去掉下划线:
^[a-z0-9-]+(.[a-z0-9-]+)*$
Done. 现在只需要用”@”把两部分连接:
^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*$
这就是完整的email认证匹配模式了,只需要调用
eregi(‘^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*$ ’,$eamil)
就可以得到是否为email了。
正则表达式的其他用法
提取字符串
ereg() and eregi() 有一个特性是允许用户通过正则表达式去提取字符串的一部分(具体用法你可以阅读手册). 比如说,我们想从 path/URL 提取文件名 – 下面的代码就是你需要:
ereg("([^/]*)$", $pathOrUrl, $regs); PHPChina 开源社区门户+Y0F c R N
echo $regs[1];
高级的代换
ereg_replace() 和 eregi_replace()也是非常有用的: 假如我们想把所有的间隔负号都替换成逗号:
ereg_replace("[ nrt]+", ",", trim($str));
- 常用正则表达式全集
- 正则表达式使用详解
- 一些常用的正则表达式
- 常用正则表达式实例
- php正则表达式学习实例
- 常用正则表达式的例子
收集了10个php正则表达式实例,希望对大家学习正则有所帮助。
1. 根据购物车中的商品Item ID,准确判断客人的原装机型号。
$title = "Replacement Canon BP-511 Camcorder Battery [Item ID:3-236-523]";
if( eregi("([Item ID:)([0-9]+)-([0-9]+)-([0-9]+)(])",$title,$arr) ){
echo "<pre>";
print_r($arr);
echo "</pre>";
}
?>
2. 匹配日期
// 分隔符可以是斜线,点,或横线
$date = "04/30/1973";
list($month, $day, $year) = split ('[/.-]', $date); // 漏洞: 04/30-1973也能匹配得上
echo "Month: $month; Day: $day; Year: $year<br />n";
?>
3. 搜索单词 web
if (preg_match ("/bwebb/i", "PHP is the website scripting language of choice.")) {
print "A match was found.";
} else {
print "A match was not found.";
}
?>
4. 从url 中取出域名
// 从 URL 中取得主机名
preg_match("/^(http://)?([^/]+)/i",
"http://www.php.net/index.html", $matches);
$host = $matches[2];
// 从主机名中取得后面两段
preg_match("/[^./]+.[^./]+$/", $host, $matches);
echo "domain name is: {$matches[0]}n";
// 本例执行后将输出: domain name is: php.net
?>
5. 你知道下面的程序输出什么?
preg_match_all ("|<[^>]+>(.*)</[^>]+>|U",
"<b>example: </b><div align=left>this is a test</div>",
$out, PREG_PATTERN_ORDER); // 注意PREG_PATTERN_ORDER和PREG_SET_ORDER的区别
print $out[0][0].", ".$out[0][1]."n";
print $out[1][0].", ".$out[1][1]."n";
echo "<pre>";
print_r($out);
?>
6. 功能: 转义正则表达式字符
$keywords = "$40 for a g3/400";
$keywords = preg_quote ($keywords, "/");
echo $keywords; // returns $40 for a g3/400
?>
7. 看人家如何用 preg_quote() 函数实现高亮显示
// 本例中,preg_quote($word) 用来使星号不在正则表达式中
// 具有特殊含义。
$textbody = "This book is *very* difficult to find.";
$word = "*very*";
$textbody = preg_replace ("/".preg_quote($word)."/",
"<b>".$word."</b>",
$textbody);
echo $textbody;
?>
8. 用回调函数执行正则表达式的搜索和替换
// 此文本是用于 2002 年的,
// 现在想使其能用于 2003 年
$text = "April fools day is 04/01/2002n";
$text.= "Last christmas was 12/24/2001n";
// 回调函数
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/2003
// Last christmas was 12/24/2002
?>
9. 在 preg_replace() 中使用索引数组
$string = "The quick brown fox jumped over the lazy dog.";
$patterns[0] = "/quick/";
$patterns[1] = "/brown/";
$patterns[2] = "/fox/";
$replacements[2] = "bear";
$replacements[1] = "black";
$replacements[0] = "slow";
print preg_replace($patterns, $replacements, $string);
/* Output
======
The bear black slow jumped over the lazy dog.
*/
/* By ksorting patterns and replacements,
we should get what we wanted. */
ksort($patterns);
ksort($replacements);
print preg_replace($patterns, $replacements, $string);
/* Output
======
The slow black bear jumped over the lazy dog.
*/
?>
10. 将 HTML 转换成文本
// $document 应包含一个 HTML 文档。
// 本例将去掉 HTML 标记,# 代码
// 和空白字符。还会将一些通用的
// HTML 实体转换成相应的文本。
$search = array ("'<script[^>]*?>.*?</script>'si", // 去掉 #
"'<[/!]*?[^<>]*?>'si", // 去掉 HTML 标记
"'([rn])[s]+'", // 去掉空白字符
"'&(quot|#34);'i", // 替换 HTML 实体
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i",
"'&#(d+);'e"); // 作为 PHP 代码运行
$replace = array ("",
"",
"1",
""",
"&",
"<",
">",
" ",
chr(161),
chr(162),
chr(163),
chr(169),
"chr(1)");
$text = preg_replace ($search, $replace, $document);
?>