第2章 字符的处理与正则表达式

在PHP中,对于字符的处理是一个很重要的部分,很多应用中都包含有字符处理的功能,而正则表达式则是有效地处理一些复杂字符操作的便利方式。本章将重点介绍PHP中的一些常见字符处理操作及正则表达式的应用。

2.1 字符类型的特殊性

在光盘配套电子书中的第3章中介绍了字符串的概念。字符串是由字符组成的,字符包括以下几种类型。

➢ 数字:例如1、2、3等。

➢ 字母:例如A、B、C、a、b、c等。

➢ 特殊字符:例如#、$、%、_、^、&等。

➢ 不可见字符:例如\n、\t、\r等。

其中,不可见字符是比较特殊的一组字符,用来控制字符串格式化输出,并不能在屏幕上看到字符本身,而只能看到字符带来的一些结果。示例代码如下。

        <?php
        echo "abcde\tfghij\rklmno\npqrst";                            //输出字符串
        ?>

运行结果如下。

        abcde    fghij
        klmno
        pqrst

由以上代码可以看出,由于不可见字符的应用使得运行结果的格式发生了变化。

2.2 字符的显示与格式化

在本书前面的例子中,已经大量使用了字符的显示方法。这里对字符的显示做一下总结。

2.2.1 字符的显示

PHP中,字符的显示主要分为两种方式,使用print和echo进行输出。print的语法格式如下所示。

        int print(str)

这里的str是用来输出的字符串,返回值永远为1。print是一个类似于函数的输出方式,但是print并不是一个真正意义上的函数。print还有一种语法格式如下。

        print str;

echo的语法格式如下所示。

        void echo(str1, str2, …)

这里的str1、str2等是用来输出的字符串,与print类似,echo也有另一种语法格式,如下所示。

        echo str1, str2, …;

使用多参数来输出多个字符串的输出结果与使用字符串连接符“.”的结果完全相同。以下代码是一个使用echo输出多个参数的例子。

        <?php
        echo "test ", "it", "\n";           //使用多参数
        echo "test "."it"."\n";             //使用连接符“.”
        ?>

上面的例子输出了两行“test it”。

echo与print基本上通用,但是有以下两点区别。

➢ 使用print的函数形式返回值为1,echo没有返回值;

➢ echo支持多参数,print不支持。

2.2.2 字符的格式化

PHP中使用sprintf函数对字符串进行格式化操作,语法格式如下。

        string sprintf(string format[, str1][, str2] …)

这里,format是要输出的字符串格式,str1、str2等是要格式化输出的其他字符串。format字符串中的格式由一般的字符和一些以“%”开头的字符构成,这些以“%”开头的字符用来指代后面的参数。这些字符包括以下几种。

➢ %b:参数将被认为是整型数,并且以二进制形式输出。

➢ %c:参数将被认为是整型数,并且以ASCII码形式输出。

➢ %d:参数将被认为是整型数,并且以有符号数形式输出。

➢ %u:参数将被认为是整型数,并且以无符号形式输出。

➢ %o:参数将被认为是整型数,并且以八进制形式输出。

➢ %x:参数将被认为是整型数,并且以十六进制形式输出,其中的字母为小写形式。

➢ %X:参数将被认为是整型数,并且以十六进制形式输出,其中的字母为大写形式。

➢ %f:参数将被认为是浮点数。

➢ %s:参数将被认为是字符串。

以下代码是一个格式化输出字符串的例子。

        <?php
        echo sprintf("This is an integer: %b, %c, %d, %u, %o, %x, %X\n", 23, 23, -23, -23, 23,
    23, 23);
        ?>

运行结果如下所示。

        This is an integer: 10111,  , -23, 4294967273, 27, 17, 17

需要注意的是如果只是为了输出格式化的字符串,可以直接用printf进行,语法与sprintf相同。不同的是printf可以直接将格式化后的字符串输出。以下代码改写了上面的例子。

        <?php
        printf("This is an integer: %b, %c, %d, %u, %o, %x, %X", 23, 23, -23, -23, 23, 23, 23)
        ?>

运行结果与前面相同。

2.3 常见的操作

对于字符串,PHP提供了多种多样的函数对其进行各种操作。这里,仅介绍一些常见的字符串操作是如何通过函数来实现的。

2.3.1 字符串重复操作——str_repeat

以下代码演示了一个简单的循环结构。

        <?php
        for($i=0;$i<10;$i++)                                  //循环输出10次*-
            echo "*-";
        ?>

运行结果如下所示。

        *-*-*-*-*-*-*-*-*-*-

对于字符串来说,使用这样的循环结构单纯地循环一个简单字符串似乎有些大材小用了。PHP针对字符串的重复提供了一个函数——str_repeat函数,其语法格式如下所示。

        string str_repeat ( string input, int multiplier)

这里input参数表示的是要重复的字符串,multiplier表示的是要重复的次数,以下代码改写了上面的例子。

        <?php
        echo str_repeat("*-", 10);                            //输出10个*-
        ?>

运行结果与前面相同。

2.3.2 字符串替换操作——str_replace和str_ireplace

本节主要介绍两个用于字符串替换的函数str_replace和str_ireplace。

1.str_replace

str_replace函数的语法格式如下。

        str_replace(search, replace, subject [, int &count])

这里,subject是要进行替换的字符串,search是要查找的内容,replace是要替换成的内容。&count是一个变量,用来接收进行替换的次数。

以下代码演示并解释了各个参数的用法。

        <?php
        //这里在字符串<body text='%body%'>里面查找%body%并将其替换成RED
        //这样最后输出的字符串就是<body text='RED'>
        //如果在Web浏览器,如IE,中浏览这个代码的运行结果,则可以看到所有的文字都是红色的
        $bodytag = str_replace("%body%", "RED", "<body text='%body%'>");
        echo $bodytag."\n";

        //这里主要是对元音字母进行消除,包括大写字母和小写字母
        $vowels = array("a", "e", "i", "o", "u", "A", "E", "I", "O", "U");
        $onlyconsonants = str_replace($vowels, "", "Welcome to Ochi!");
        echo $onlyconsonants."\n";

        //这里是对句子$phrase中的关键字进行1对1的匹配替换
        //这个操作根据两个数组的元素顺序进行一次匹配并替换
        $phrase  = "You should eat fruits, vegetables, and fiber every day.";
        $healthy = array("fruits", "vegetables", "fiber");
        $yummy   = array("pizza", "beer", "ice cream");
        $newphrase = str_replace($healthy, $yummy, $phrase);
        echo $newphrase."\n";

        //这里主要是对句子中ll的替换,变量$count用来接收替换的次数
        //也就是有几个项目被替换了
        $str = str_replace("ll", "tt", "Polly said she loves Golly!", $count);
        echo $count;
        ?>

这段代码在Web浏览器中的运行结果如下所示(字符颜色为红色)。

        Wlcm t Och! You should eat pizza, beer, and ice cream every day. 2

如果查看源文件,则可以看到如下的结果。

        <body text='RED'>
        Wlcm t Och!
        You should eat pizza, beer, and ice cream every day.
        2

2.str_ireplace

str_replace 函数的用途非常广泛,在搜索引擎和模板式网站系统中尤其常见。但是str_replace 有一个很大的不足就是 str_replace 是大小写敏感的。因此如果要实现大小写不敏感的信息替换就会非常麻烦。例如,搜索引擎系统中标亮查找的关键字就非常麻烦。为此,PHP在5.0时引进了大小写不敏感的str_ireplace函数。

str_ireplace函数在用法上与str_replace完全相同,可以看做大小写不敏感的str_replace。以下代码对上边的str_replace函数例子中的前两个例子用str_ireplace进行了改写。

        <?php
        //这里在字符串<body text='%BODY%'>里面查找%body%并将其替换成RED
        $bodytag = str_ireplace("%body%", "RED", "<body text='%BODY%'>");
        echo $bodytag."\n";

        //这里主要是对元音字母进行消除,包括大写字母和小写字母
        //因为使用了大小写不敏感的str_ireplace函数,虽然在array中没有指定大写的元音字母
        //在查找中,大写的元音字母依然会被替换掉
        $vowels = array("a", "e", "i", "o", "u");
        $onlyconsonants = str_ireplace($vowels, "", "Welcome to Ochi!");
        echo $onlyconsonants."\n";
        ?>

运行结果与前面相同。需要注意的是这两个替换函数不仅支持字符串的替换,还可以用于二进制数据的替换,用法与字符串替换相同。

2.3.3 字符串分解操作——str_split

在实际应用中,经常需要将一个很大的字符串分解成一些小的字符串进行处理。PHP中,使用str_split函数对字符串进行分解,其语法格式如下所示。

        array str_split(string str [, int split_length])

这里,str是要进行分解的字符串,split_length是分解的长度,也就是每小段有多长。如果不指定 split_length,默认为1,也就是函数会将字符串分解成一个个的单一字符。以下代码演示了这个函数的基本用法。

        <?php
        $str = "Hello World";
        $arr1 = str_split($str);                              //分解$str,每个元素为1个字符
        $arr2 = str_split($str, 3);                           //分解$str,每个元素为3个字符
        print_r($arr1);
        print_r($arr2);
        ?>

运行结果如下所示。

        Array
        (
            [0] => H
            [1] => e
            [2] => l
            [3] => l
            [4] => o
            [5] =>
            [6] => W
            [7] => o
            [8] => r
            [9] => l
            [10] => d
        )
        Array
        (
            [0] => Hel
            [1] => lo
            [2] => Wor
            [3] => ld
        )

可以看出,$arr1 中储存的是字符串的单一字符,$arr2 中储存的是字符串按照指定的长度3进行分解得到的结果。

2.3.4 字符串单词数的计算函数——str_word_count

上一节介绍了 str_split 的用法,但是在通常的应用中,往往需要实现一个更加复杂的需求——分词。因为每个词的字符数目不尽相同,所以str_split函数无法实现此功能。在PHP中,可以使用str_word_count函数实现这一功能,其语法格式如下所示。

        str_word_count (string str [, int format])

这里,str是要进行分解或者计算的字符串,format包括以下两种。

➢ 返回一个包含str中全部单词的数组,数组的键值按照顺序排列。

➢ 返回一个包含str中全部单词的数组,数组的键值反映了单词所在的位置。

以下代码演示了这个函数的基本用法。

        <?php
        $str = "This is a test case";
        //这里计算出在$str中有多少个单词
        $a = str_word_count($str);
        //这里返回的是$str的全部单词
        $b = str_word_count($str, 1);
        //这里返回的是$str的全部单词,并且数组的键值反映了单词所在的位置
        $c = str_word_count($str, 2);
        print_r($a);
        print_r($b);
        print_r($c);
        ?>

运行结果如下所示。

        5
        Array
        (
            [0] => This
            [1] => is
            [2] => a
            [3] => test
            [4] => case
        )
        Array
        (
            [0] => This
            [5] => is
            [8] => a
            [10] => test
            [15] => case
        )

2.3.5 字符串查找操作——strstr

前面介绍了字符串替换函数的用法,这里介绍字符串查找。PHP 中使用 strstr 和 stristr函数进行字符串查找操作。

strstr函数的语法格式如下所示。

        string strstr(string str, string search)

这里,str是要进行查找的字符串,search是要查找的内容。这个函数返回自找到的第一个完全匹配位置以后的全部内容。以下代码演示了这个函数的基本用法。

        <?php
        //在$num中,2334出现了两次,而strstr函数将只找到第一次出现的位置
        $num = "11223344556622334455";
        $do = strstr($num, "2334");
        echo $do;
        ?>

代码运行结果如下。

        23344556622334455

与替换函数str_replace类似,strstr函数也是大小写敏感的。为此,PHP提供了一个类似于str_ireplace的大小写不敏感的stristr函数,用法与strstr函数相同。

2.3.6 获得字符串长度——strlen

strlen函数用来获得字符串的长度,其语法格式如下所示。

        int strlen(string str)

这里,str是要进行长度计算的字符串。值得注意的是,这个函数不同于C语言中的字符串长度计算函数会把结束符考虑在内,这个函数计算的是字符串中真正出现的字符长度(包括首尾空格)。

以下代码演示了这个函数的基本用法。

        <?php
        $str = 'abcdef';
        echo "'abcdef'的长度是" . strlen($str) . "<br />";
        $str = ' ab cd ';
        echo "' ab cd '的长度是" . strlen($str) . "<br />";
        ?>

运行结果如下所示。

        'abcdef'的长度是6
        ' ab cd '的长度是7

2.3.7 获得字符串子串——substr

在实际应用中,通常需要截取某一段字符串,substr 函数用来截取一部分字符串,其语法格式如下。

        string substr(string str, int start [, int length])

这里,str是要进行截取的字符串。start是开始的字符位置。length是要截取的长度,如果不指定length则默认为截取到字符串末尾。需要注意的是字符串的第一个字符的位置为0。

以下代码演示并介绍了这个函数的基本用法。

        <?php
        //从第1位(第2个字符)开始截取一直到末尾
        echo substr("abcdef", 1)."<br>";
        //从第1位(第2个字符)开始截取3个字符
        echo substr("abcdef", 1, 3)."<br>";
        //从第0位开始截取10个字符,如果字符串不满10个字符则截取到末尾
        echo substr("abcdef", 0, 10)."<br>";
        //从-1位开始截取到末尾,当开始位为负数时,从后向前数
        //最末一位为-1,依次为-2,-3。
        echo substr("abcdef", -1)."<br>";
        echo substr("abcdef", -3, 1)."<br>";
        //如果长度为负数,则该数字所表示的字符及其后边的字符将都被省略
        echo substr("abcdef", 0, -1)."<br>";
        echo substr("abcdef", 1, -2)."<br>";
        echo substr("abcdef", -3, -1)."<br>";
        ?>

代码运行结果如下。

        bcdef
        bcd
        abcdef
        f
        d
        abcde
        bcd
        de

2.4 正则表达式简介

正则表达式是描述字符串集的字符串。例如,正则表达式“*PHP*”描述所有包含“PHP”,并且前面或后面跟零个或多个字符的字符串。PHPMyadmin、MyPHP、ZendPHPframework或PHP本身都是例子。英文句号“.”匹配任何字符,“+”类似“*”,但至少要一个字符,所以“+PHP+”只能匹配前述的“ZendPHPframework”字符串。[a-z]指一个匹配范围,所以[a-zA-Z_0-9]匹配字母、数字或下画线,也可以将它写成“\w”。“\w+”匹配至少有一个字符的单词字符序列。例如,正则表达式“^[a-zA-Z_]\w*$”。专用字符“^”意思是“以...开始”,“$”意思是“结尾”,所以“^[a-zA-Z_]\w*$”的意思就是:以字母或下画线开始的字母、数字或下画线字符串。

正则表达式在对输入进行有效性验证时非常有用。除了前面介绍的\w 以外,\d 匹配数字,{n}匹配重复n次。例如,字符串“^8\d{5}$”匹配以8开头的6位数字。

2.5 正则表达式与字符操作综合应用

正则表达式可以看做是一种特殊的格式化字符串,因此正则表达式也具有一些字符操作的特性。本节将介绍如何通过正则表达式达到对字符进行操作的目的。

与Perl语言类似,正则表达式的函数规定表达式必须被包含在定界符中,如使用斜线“/”作为定界符。PHP 规定,任何字母、数字或反斜线(\)都不可以作为定界符,而 Perl 风格的“()”,“{}”,“[]”和“<>”等定界符在PHP中仍然适用。如果作为定界符的字符必须被用在表达式本身中,则需要用反斜线(\)转义。例如,正则表达式“/<\/\w-+php>/”。在这个正则表达式中,使用斜线(/)作为定界符,在该正则表达式中就用到了斜线(/),这种情况下,使用反斜线(\)对其进行转义。

2.5.1 获得与模式匹配的数组单元——preg_grep

preg_grep函数用来获得与模式匹配的数组单元,其语法格式如下所示。

        array preg_grep(string pattern, array input)

这里,pattern 是用来匹配的正则表达式,input 是用来匹配的数组。需要注意的是,preg_grep函数返回的结果使用从输入数组来的键名进行索引。以下代码演示了这个函数的基本用法。

        <?php
        //首先定义一个数组并赋值,需要将完整的浮点数输出
        $old_array[0] = "1234";
        $old_array[1] = "123.4";
        $old_array[2] = "12.34";
        $old_array[3] = "0.1234";
        $old_array[4] = ".123";
        $old_array[5] = "123.";
        //这里的正则表达式使用了加号,这样如果小数点前或者后为空,则不会被返回
        $new_array = preg_grep ("/^(\d+)?\.\d+$/", $old_array);
        print_r($new_array);
        ?>

代码运行结果如下。

        Array
        (
            [1] => 123.4
            [2] => 12.34
            [3] => 0.1234
            [4] => .123
        )

由以上代码的运行结果可以看出,$old_array[0]与$old_array[5]被过滤掉了。

2.5.2 进行全局正则表达式匹配——preg_match_all

preg_match_all函数用来进行全局正则表达式的匹配,其语法格式如下所示。

        int preg_match_all(string pattern, string input, array matches [, int flags])

这里,pattern是用来匹配的正则表达式,input是用来匹配的字符串,matches是匹配结果的存储数组,flag可以是以下3个标记的任意组合。

➢ PREG_PATTERN_ORDER:其结果使$matches[0]用于存储全部模式匹配的数组,$matches[1]用于存储其第一个子模式所匹配的字符串组成的数组,$matches[2]等之后的数组元素的存储以此类推。

➢ PREG_SET_ORDER:其结果使$matches[0]用来存储第一组匹配项的数组,$matches[1]用来存储第二组匹配项的数组,$matches[2]等之后的数组元素的存储以此类推。

➢ PREG_OFFSET_CAPTURE:这个标记是一个可选标记,如果选择这个标记,则在输出每一个匹配结果的同时也将返回其附属的字符串偏移量。

需要注意的是如果在函数中不设定标记,则默认为 PREG_PATTERN_ORDER。如果在函数中同时使用了两个以上标记,则没有任何意义。以下代码演示了这个函数的基本用法。

        <?php
        //首先将要进行正则表达式匹配的字符串存入$str变量,需要把其中的7位电话号码全部匹配出来
        $str = "Please call me at 507-4235 or 716-6577";
        //使用PREG_PATTERN_ORDER模式进行匹配
        preg_match_all ("/\d{3}(\-\d{4})/", $str, $phones, PREG_PATTERN_ORDER);
        print_r($phones);
        echo "\n";
        //使用PREG_SET_ORDER模式进行匹配
        preg_match_all ("/\d{3}(\-\d{4})/", $str, $phones, PREG_SET_ORDER);
        print_r($phones);
        ?>

代码运行结果如下。

        Array
        (
            [0] => Array
                (
                  [0] => 507-4235
                  [1] => 716-6577
                )

            [1] => Array
                (
                  [0] => -4235
                  [1] => -6577
                )

        )

        Array
        (
            [0] => Array
                (
                  [0] => 507-4235
                  [1] => -4235
                )

            [1] => Array
                (
                  [0] => 716-6577
                  [1] => -6577
                )

        )

由以上代码运行结果的比较可以看出两种标记的区别所在。同时,从上面的两组结果也可以看出,在字符串$str 中的两组电话号码全部被成功地匹配出来了。以下代码演示了PREG_OFFSET_CAPTURE的用法。

        <?php
        //首先将要进行正则表达式匹配的字符串存入$str变量,需要把其中的7位电话号码全部匹配出来
        $str = "Please call me at 507-4235 or 716-6577";
        //使用PREG_OFFSET_CAPTURE模式进行匹配
        preg_match_all ("/\d{3}(\-\d{4})/", $str, $phones, PREG_OFFSET_CAPTURE);
        print_r($phones);
        ?>

代码运行结果如下。

        Array
        (
            [0] => Array
                (
                  [0] => Array
                      (
                          [0] => 507-4235
                          [1] => 18
                      )

                  [1] => Array
                      (
                          [0] => 716-6577
                          [1] => 30
                      )

                )

            [1] => Array
                (
                  [0] => Array
                      (
                          [0] => -4235
                          [1] => 21
                      )

                  [1] => Array
                      (
                          [0] => -6577
                          [1] => 33

                      )
                )

        )

从以上代码运行结果可以看出,使用PREG_OFFSET_CAPTURE已经使结果数组发生了变化,由原来的二维数组变为了新的三维数组,偏移量被当做数组的一部分输出。

2.5.3 进行正则表达式匹配——preg_match

preg_match函数用来进行正则表达式匹配。与preg_match_all函数不同,preg_match函数在第一次匹配后将停止搜索,其语法格式如下。

        int preg_match(string pattern, string input, array matches [, int flags])

这里,preg_match的函数用法与preg_match_all函数完全相同。需要注意的是这里的flags只能使用PREG_OFFSET_CAPTURE。以下代码使用preg_match函数重写了前面的例子,演示了这个函数的基本用法。

        <?php
        //首先将要进行正则表达式匹配的字符串存入$str变量,需要把其中的第一个7位电话号码全部匹配出来
        $str = "Please call me at 507-4235 or 716-6577";
        preg_match("/\d{3}(\-\d{4})/", $str, $phones, PREG_OFFSET_CAPTURE);
        print_r($phones);
        ?>

运行结果如下所示。

        Array
        (
            [0] => Array
                (
                  [0] => 507-4235
                  [1] => 18
                )

            [1] => Array
                (
                  [0] => -4235
                  [1] => 21
                )

        )

比较这个新的运行结果,只包含了前面运行结果的第一部分。由此可见,preg_match函数在得到第一个匹配项的时候就停止了匹配。

2.5.4 转义正则表达式字符——preg_quote

preg_quote 函数用来进行正则表达式的转义。preg_quote 函数用于将字符串中所有具有正则表达式意义的字符进行转义。在实际应用中,如果需要用动态生成的字符串来作为正则表达式进行模式匹配等操作,则可以用此函数转义其中可能包含的一些特殊字符。这些特殊字符包括:“.”“\\”“+”“*”“?”“[]”“^”“$”“()”“{}”“=”“!”“<>”“|”“:”等。preg_quote函数的语法格式如下所示。

        string preg_quote(string str [, string delimiter])

这里,参数str是用来进行字符转义的正则表达式,delimiter是其他需要转义的字符。以下代码演示了这个函数的基本用法。

        <?php
        $str = preg_quote("/\d{3}(\-\d{4})/");
        echo $str;
        ?>

运行结果如下。

        /\\d\{3\}\(\\-\\d\{4\}\)/

如果需要对其他的字符进行转义,则需要使用参数delimiter。以下代码对上面字符串中的“3”也进行了转义。

        <?php
        $str = preg_quote("/\d{3}(\-\d{4})/",”3”);
        echo $str;
        ?>

运行结果如下所示。

        /\\d\{\3\}\(\\-\\d\{4\}\)/

比较两段代码的运行结果可以看出,第二个例子的运行结果中的“3”前面,多了一个转义符“\”。

2.5.5 执行正则表达式的搜索和替换的函数——preg_replace

preg_replace与前面的preg_match函数使用方法类似,但是还提供了字符串的替换功能,其语法格式如下所示。

        preg_replace(pattern, replacement, subject [, int limit])

这里,参数pattern是进行匹配的正则表达式,replacement是要将匹配部分替换成的字符串或者正则表达式,subject是要被匹配的字符串,limit是要进行的匹配次数。以下代码演示了这个函数的基本用法。

        <?php
        $string = "Today is Aug 11, 2006.";
        $pattern = "/(\w+) (\d+), (\d+)/i";
        $replacement = "today";
        print preg_replace($pattern, $replacement, $string);
        ?>

运行结果如下所示。

        Today is today.

2.5.6 通过回调函数执行正则表达式的搜索和替换——preg_replace_callback

preg_replace_callback 的用法几乎和preg_replace函数一样。但是,使用preg_replace_callback函数可以获得比preg_replace更完善的替换功能。preg_replace的替换只是基本的字符串间的计算,而 preg_replace_callback 函数可以将要替换的字符串传入一个函数进行处理,并将处理后的结果进行替换。根据callback函数的功能,这个函数提供了更好的灵活性。preg_replace_callback函数的语法格式如下。

        preg_replace_callback(pattern, callback, subject [, int limit])

这里,参数callback是一个callback函数。所谓callback函数就是用来处理匹配字符串的函数。以下代码演示了这个函数的基本用法。

        <?php
          //这个例子实现了字符串中7位电话号码的自动升位
          //升位规则为首位+8
          $text = "Our telephone numbers are 4355213 and 3566721.";
          //回调函数实现电话号码的升位规则
        function upgrade($matches)
        {
            return "8".$matches[0];                                     //$matches[0] 是完整的
    匹配项
          }
        //输出处理后的字符串
          echo preg_replace_callback("|\d{10}|","upgrade",$text);
        ?>

这段代码的运行结果如下。

        Our telephone numbers are 84355213 and 83566721.

上面的例子中,upgrade函数就是callback函数,电话号码被匹配出来以后,传递给upgrade函数进行处理,处理后的结果被放回到字符串中。

2.5.7 用正则表达式进行字符串分割——preg_split

preg_split提供了用正则表达式分割字符串的功能,其语法格式如下。

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

这里,参数 pattern 是进行匹配的正则表达式,subject 是要被匹配的字符串,limit 是要进行的匹配次数,flags是下列标记的组合。

➢ PREG_SPLIT_NO_EMPTY:如果设定了本标记,匹配结果中的非空字符串将不会被返回。

➢ PREG_SPLIT_DELIM_CAPTURE:如果设定了本标记,在进行匹配时,定界符模式中的括号表达式也会被返回。

➢ PREG_SPLIT_OFFSET_CAPTURE:如果设定了本标记,返回每个出现的匹配结果的同时也将获取其附属的字符串偏移量。这与前面同名参数的使用方法相同。

以下代码演示了这个函数及其3种标记的基本用法。

        <?php
        //本例实现了一个对英文句子分词的功能,并且对句尾句号进行了过滤
        $str = 'today is a nice day.';
        $chars = preg_split('/[ ,.]/', $str, -1, PREG_SPLIT_NO_EMPTY);
        print_r($chars);
        print("\n");
        $chars = preg_split('/[ ,.]/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
        print_r($chars);
        print("\n");
        $chars = preg_split('/[ ,.]/', $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
        print_r($chars);
        print("\n");
        ?>

代码运行结果如下。

        Array
        (
            [0] => today
            [1] => is
            [2] => a
            [3] => nice
            [4] => day
        )

        Array
        (
            [0] => today
            [1] => is
            [2] => a
            [3] => nice
            [4] => day
            [5] =>
        )
        Array
        (
            [0] => Array
                (
                    [0] => today
                    [1] => 0
                )

            [1] => Array
                (
                    [0] => is
                    [1] => 6
                )
            [2] => Array

                (
                    [0] => a
                    [1] => 9
                )

            [3] => Array
                (
                    [0] => nice
                    [1] => 11
                )
            [4] => Array
                (
                    [0] => day
                    [1] => 16
                )

            [5] => Array
                (
                    [0] =>
                    [1] => 20
                )

        )

读者可以从比较上面3种标记的运行结果中体会到其中的不同。

2.6 字符操作的注意事项

本章的前面介绍了字符操作的一些方法,以及正则表达式的基本使用。但是,由于PHP是一种脚本语言,因此在实际的字符操作时往往不能在浏览器上看到需要的结果,如以下代码所示。

        <?php
        echo "This is a test.\nTest again.";
        ?>

预期的运行结果如下所示。

        This is a test.
        Test again.

但是,由于浏览器会将其作为HTML脚本处理,因而在浏览器上的输出结果如图2-1所示。

图2-1 浏览器的输出结果

可以看到,换行符不见了,被一个空格取而代之。在实际应用中,这种情况非常多见,读者需要注意。解决这个问题可以使用以下3种方式。

(1)通过直接存储HTML标签的方法,如下面的例子。

        <?php
        echo "This is a test.<br>Test again.";
        ?>

(2)通过使用<pre>标签的方法,如下面的例子。

        <?php
        echo "<pre>This is a test.\nTest again.</pre>";
        ?>

(3)通过使用str_replace进行替换的方法,如下面的例子。

        <?php
        $str = "This is a test.\nTest again.";
        echo str_replace("\n", "<br>", $str);
        ?>

读者也可以自行编写一个自定义函数用于将字符串中的所有需要替换的特殊字符全部替换过来。这种替换在页面的显示和对用户数据的处理上很有必要,如下面的例子所示。

        <?php
        echo "This is a test. <Author: Simon>";
        ?>

由于“<”和“>”在 HTML 解析时被当做了标签,因此在浏览器上浏览时只能看到如下所示的输出。

        This is a test.

对于这个问题,可以使用上面的方法进行替换,如下面的例子所示。

        <?php
        $str = "This is a test. <Author: Simon>";
        $str = str_replace("<", "&lt", $str);
        $str = str_replace(">", "&gt", $str);
        echo $str;
        ?>

运行结果如下。

        This is a test. <Author: Simon>

由于这个问题在Web项目开发中非常普遍,因而PHP提供了htmlspecialchars函数用来替换一些 HTML 中的常用特殊字符,例如大于号“>”、小于号“<”以及连接符“&”等,该函数语法格式如下所示。

        string htmlspecialchars(string str)

该函数可以将HTML中的一些特殊字符替换成浏览器可以显示的字符,如下面的例子所示。

        <?php
        $str = "This is a test. <Author: Simon>";
        $str = htmlspecialchars($str);
        echo $str;
        ?>

运行结果与前面的相同。

2.7 小结

本章介绍了PHP中的字符操作,其中结合正则表达式的操作是本章的重点也是难点。使用正则表达式可以有效地进行一些特殊的字符操作,但是正则表达式的书写对于初学者来说是一个很大的难点。读者需要慢慢体会正则表达式中的概念,熟练使用正则表达式以后才能熟练地进行各种字符操作。