PHP-正则表达式

PHP-正则表达式

一 简介

根据一定的规则来匹配(查找)确认一些字符串,如要求用户输入的 QQ 号码为数字且至少 5 位。用于描述这些规则的工具就是正则表达式。

元字符(^ 、\d 及 $ 等这些符号,代表了特定的匹配意义,我们称之为元字符)

^:表示匹配字符串的开始,也即该字符串是独立的开始而不是包含在某个字符串之内 $:表示匹配字符串的结束,也即该字符串是独立的结束

元字符说明
.匹配除换行符意外的任意字符
\w匹配字母或数字或下划线
\s匹配任意的空白符
\d匹配数字
\b匹配单词的开始或结束
^匹配字符串的开始
$匹配字符串的结束
[x]匹配x字符,如匹配字符串中的 a、b 和 c 字符
\W\w的反义,即匹配任意非字母,数字,下划线和汉字的字符
\S\s的反义,即匹配任意非空白符的字符
\D\d的反义,即匹配任意非数字的字符
\B\b的反义,即不是单词开头或结束的位置
[^x]匹配除了 x 意外的任意字符,如 [^abc] 匹配除了 abc 这几个字母之外的任意字符

注:当匹配元字符时,需要用转义字符“\”

二 相关操作和函数

(一)重复(重复规则来表达循环匹配)

重复说明
*重复零次或更多次
+重复 1 次或更多次
?重复零次或 1 次
{n}重复 n 次
{n,}重复 n 次或更多次
{n,m}重复 n 到 m 次

(二)分枝(分枝是指制定几个规则,如果满足任意一种规则,则都当作匹配成功。具体来说就是用 | 符号把各种规则分开,且条件从左至右匹配)

注:分枝当满足包含时,需注意规则的先后的顺序

例:

美国的邮政编码的规则是 5 个数字或者 5 个数字连上 4 个数字,如 12345 或者 54321-1234 ,如果要匹配所有的邮编,则正确的正则表达式为:

\d{5}-\d{4}|\d{5}
//错误写法
\d{5}|\d{5}-\d{4}

错误写法,只能匹配到 5 位数字及 9 位数字的前 5 位数字的情况,而不能匹配 9 位数字的邮编。

(三)分组(用小括号将一些规则括起来当作分组,分组可以作为一个元字符来看待)

匹配正确的 IP 地址:

((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)
(四)贪婪和懒惰

正则表达式默认的情况下,会在满足匹配条件下尽可能的匹配更多内容。如 a.*b,用他来匹配 aabab ,它会匹配整个 aabab ,而不会只匹配到 aab 为止,这就是贪婪匹配。

与贪婪匹配对应的是,在满足匹配条件的情况下尽可能的匹配更少的内容,这就是懒惰匹配。

懒惰限定符说明
*?重复任意次,但尽可能少重复
+?重复 1 次或更多次,但尽可能少重复
??重复 0 次或 1 次,但尽可能少重复
{n,}重复 n 次以上,但尽可能少重复
{n,m}重复 n 到 m 次,但尽可能少重复

(五)模式修正符(对正则表达式的一些补充说明)

模式修正符说明
i模式中的字符将同时匹配大小写字母
m字符串视为多行
s将字符串视为单行,换行符作为普通字符
x将模式中的空白忽略
epreg_replace() 函数在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。
A强制仅从目标字符串的开头开始匹配
D模式中的 $ 元字符仅匹配目标字符串的结尾
U匹配最近的字符串
u模式字符串被当成 UTF-8

(六)函数操作

定界符

Perl 兼容模式的正则表达式函数,其正则表达式需要写在定界符中。任何不是字母、数字或反斜线()的字符都可以作为定界符,通常我们使用 / 作为定界符。

preg_match()

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

语法:

int preg_match( string pattern, string subject [, array matches ] )
参数说明:
参数说明
pattern正则表达式
subject需要匹配检索的对象
matches可选,存储匹配结果的数组, $matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推

例子 1 :

<?php
if(preg_match("/php/i", "PHP is the web scripting language of choice.", $matches)){
    print "A match was found:". $matches[0];
} else {
    print "A match was not found.";
}
?>

浏览器输出:

A match was found: PHP

preg_match_all()

preg_match_all() 函数用于进行正则表达式全局匹配,成功返回整个模式匹配的次数(可能为零),如果出错返回 FALSE 。

语法:

int preg_match_all( string pattern, string subject, array matches [, int flags ] ) 
参数说明:
参数说明
pattern正则表达式
subject需要匹配检索的对象
matches存储匹配结果的数组
flags

可选,指定匹配结果放入 matches 中的顺序,可供选择的标记有:

  1. PREG_PATTERN_ORDER:默认,对结果排序使 $matches[0] 为全部模式匹配的数组,$matches[1] 为第一个括号中的子模式所匹配的字符串组成的数组,以此类推
  2. PREG_SET_ORDER:对结果排序使 $matches[0] 为第一组匹配项的数组,$matches[1] 为第二组匹配项的数组,以此类推
  3. PREG_OFFSET_CAPTURE:如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量

preg_replace()

preg_replace() 函数用于正则表达式的搜索和替换。

语法:

mixed preg_replace( mixed pattern, mixed replacement, mixed subject [, int limit ] ) 
参数说明:
参数说明
pattern正则表达式
replacement替换的内容
subject需要匹配替换的对象
limit可选,指定替换的个数,如果省略 limit 或者其值为 -1,则所有的匹配项都会被替换

补充说明

  1. replacement 可以包含 \\n 形式或 $n 形式的逆向引用,首选使用后者。每个此种引用将被替换为与第 n 个被捕获的括号内的子模式所匹配的文本。n 可以从 0 到 99,其中 \\0 或 $0 指的是被整个模式所匹配的文本。对左圆括号从左到右计数(从 1 开始)以取得子模式的数目。
  2. 对替换模式在一个逆向引用后面紧接着一个数字时(如 \\11),不能使用 \\ 符号来表示逆向引用。因为这样将会使 preg_replace() 搞不清楚是想要一个 \\1 的逆向引用后面跟着一个数字 1 还是一个 \\11 的逆向引用。解决方法是使用 \${1}1。这会形成一个隔离的 $1 逆向引用,而使另一个 1 只是单纯的文字。
  3. 上述参数除 limit 外都可以是一个数组。如果 pattern 和 replacement 都是数组,将以其键名在数组中出现的顺序来进行处理,这不一定和索引的数字顺序相同。如果使用索引来标识哪个 pattern 将被哪个 replacement 来替换,应该在调用 preg_replace() 之前用 ksort() 函数对数组进行排序。

例子 1 :

<?php
$str = "The quick brown fox jumped over the lazy dog.";
$str = preg_replace('/\s/','-',$str);
echo $str;
?>

输出结果为:

The-quick-brown-fox-jumped-over-the-lazy-dog.

例子 2 ,使用数组:

<?php
$str = "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, $str);
/*输出:
The bear black slow jumped over the lazy dog.
*/
ksort($replacements);
print preg_replace($patterns, $replacements, $str);
/*输出:
The slow black bear jumped over the lazy dog.
*/
?>

preg_split()

preg_ split() 函数用于正则表达式分割字符串。

语法:

array preg_split( string pattern, string subject [, int limit [, int flags]] ) 

返回一个数组,包含 subject 中沿着与 pattern 匹配的边界所分割的子串。

参数说明:
参数说明
pattern正则表达式
subject需要匹配分割的对象
limit可选,如果指定了 limit ,则最多返回 limit 个子串,如果 limit 是 -1,则意味着没有限制,可以用来继续指定可选参数 flags
flags

设定 limit 为 -1 后可选,可以是下列标记的任意组合(用按位或运算符 | 组合):

  1. PREG_SPLIT_NO_EMPTY:preg_split() 只返回非空的成分
  2. PREG_SPLIT_DELIM_CAPTURE:定界符模式中的括号表达式也会被捕获并返回
  3. PREG_SPLIT_OFFSET_CAPTURE:对每个出现的匹配结果也同时返回其附属的字符串偏移量。注意这改变了返回的数组的值,使其中的每个单元也是一个数组,其中第一项为匹配字符串,第二项为其在 subject 中的偏移量。

例子 1 :

<?php
$str = "php mysql,apache ajax";
$keywords = preg_split("/[\s,]+/", $str);
print_r($keywords);
?>
输出结果为:
Array
(
    [0] => php
    [1] => mysql
    [2] => apache
    [3] => ajax
)

preg_split()

preg_ split() 函数用于正则表达式分割字符串。

语法:

array preg_split( string pattern, string subject [, int limit [, int flags]] ) 

返回一个数组,包含 subject 中沿着与 pattern 匹配的边界所分割的子串。

参数说明:
参数说明
pattern正则表达式
subject需要匹配分割的对象
limit可选,如果指定了 limit ,则最多返回 limit 个子串,如果 limit 是 -1,则意味着没有限制,可以用来继续指定可选参数 flags
flags

设定 limit 为 -1 后可选,可以是下列标记的任意组合(用按位或运算符 | 组合):

  1. PREG_SPLIT_NO_EMPTY:preg_split() 只返回非空的成分
  2. PREG_SPLIT_DELIM_CAPTURE:定界符模式中的括号表达式也会被捕获并返回
  3. PREG_SPLIT_OFFSET_CAPTURE:对每个出现的匹配结果也同时返回其附属的字符串偏移量。注意这改变了返回的数组的值,使其中的每个单元也是一个数组,其中第一项为匹配字符串,第二项为其在 subject 中的偏移量。

例子 1 :

<?php
$str = "php mysql,apache ajax";
$keywords = preg_split("/[\s,]+/", $str);
print_r($keywords);
?>

输出结果为:

Array
(
    [0] => php
    [1] => mysql
    [2] => apache
    [3] => ajax
)

例子 2 :

<?php
$str = 'string';
$chars = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);
print_r($chars);
?>

输出结果为:

(
    [0] => s
    [1] => t
    [2] => r
    [3] => i
    [4] => n
    [5] => g
)

例子 3 :

<?php
$str = "php mysql,apache ajax";
$keywords = preg_split("/[\s,]+/", $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
print_r($keywords);
?>

输出结果为:

Array
(
    [0] => Array
        (
            [0] => php
            [1] => 0
        )
 
    [1] => Array
        (
            [0] => mysql
            [1] => 4
        )
 
    [2] => Array
        (
            [0] => apache
            [1] => 10
        )
 
    [3] => Array
        (
            [0] => ajax
            [1] => 17
        )
)

split()

split() 函数同 preg_split() 类似,用正则表达式将字符串分割到数组中,返回一个数组,但推荐使用 preg_split() 。

(七)常用正则表达式

表单验证匹配

验证账号,字母开头,允许 5-16 字节,允许字母数字下划线:^[a-zA-Z][a-zA-Z0-9_]{4,15}$

验证账号,不能为空,不能有空格,只能是英文字母:^\S+[a-z A-Z]$

验证账号,不能有空格,不能非数字:^\d+$

验证用户密码,以字母开头,长度在 6-18 之间:^[a-zA-Z]\w{5,17}$

验证是否含有 ^%&',;=?$\ 等字符:[^%&',;=?$\x22]+

匹配Email地址:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

匹配腾讯QQ号:[1-9][0-9]{4,}

匹配日期,只能是 2004-10-22 格式:^\d{4}\-\d{1,2}-\d{1,2}$

匹配国内电话号码:^\d{3}-\d{8}|\d{4}-\d{7,8}$

评注:匹配形式如 010-12345678 或 0571-12345678 或 0831-1234567

匹配中国邮政编码:^[1-9]\d{5}(?!\d)$

匹配身份证:\d{14}(\d{4}|(\d{3}[xX])|\d{1})

评注:中国的身份证为 15 位或 18 位

不能为空且二十字节以上:^[\s|\S]{20,}$

字符匹配

匹配由 26 个英文字母组成的字符串:^[A-Za-z]+$

匹配由 26 个大写英文字母组成的字符串:^[A-Z]+$

匹配由 26 个小写英文字母组成的字符串:^[a-z]+$

匹配由数字和 26 个英文字母组成的字符串:^[A-Za-z0-9]+$

匹配由数字、26个英文字母或者下划线组成的字符串:^\w+$

匹配空行:\n[\s| ]*\r

匹配任何内容:[\s\S]*

匹配中文字符:[\x80-\xff]+ 或者 [\xa1-\xff]+

只能输入汉字:^[\x80-\xff],{0,}$

匹配双字节字符(包括汉字在内):[^\x00-\xff]

匹配数字

只能输入数字:^[0-9]*$

只能输入n位的数字:^\d{n}$

只能输入至少n位数字:^\d{n,}$

只能输入m-n位的数字:^\d{m,n}$

匹配正整数:^[1-9]\d*$

匹配负整数:^-[1-9]\d*$

匹配整数:^-?[1-9]\d*$

匹配非负整数(正整数 + 0):^[1-9]\d*|0$

匹配非正整数(负整数 + 0):^-[1-9]\d*|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)$

匹配非负浮点数(正浮点数 + 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$

其他

匹配HTML标记的正则表达式(无法匹配嵌套标签):<(\S*?)[^>]*>.*?</\1>|<.*? />

匹配网址 URL :[a-zA-z]+://[^\s]*

匹配 IP 地址:((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)

匹配完整域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?

详解:http://www.5idev.com/p-php_regular_syntax_1.shtml