ch04 字符串操作与正则表达式
文章目录
字符串操作与正则表达式
使用PHP的字符串函数来格式化和操作文本;使用字符串函数或正则表达式来搜索(替换)单词、短语或字符串的其他模式。
创建一个示例应用:智能表单邮件
<!-- feedback.html -->
<!DOCTYPE html>
<html>
<head>
<title>Bob's Auto Parts - Customer Feedback</title>
</head>
<body>
<h1>Customer Feedback</h1>
<p>Please tell us what you think.</p>
<form action="processfeedback.php" method="post">
<p><strong>Your name:</strong><br/>
<input type="text" name="name" size="40" /></p>
<p><strong>Your email address:</strong><br/>
<input type="text" name="email" size="40" /></p>
<p><strong>Your feedback:</strong><br/>
<textarea name="feedback" rows="8" cols="40">
</textarea></p>
<p><input type="submit" value="Send Feedback" /></p>
</form>
</body>
</html>
<!-- processfeedback.php -->
<?php
//create short variable names
$name = $_POST['name'];
$email = $_POST['email'];
$feedback = $_POST['feedback'];
//set up some static information
$toaddress = "aaa@qq.com";
$subject = "Feedback from web site";
$mailcontent = "Customer name: ".filter_var($name)."\n".
"Customer email: ".$email."\n".
"Customer comments:\n".$feedback."\n";
$fromaddress = "From: aaa@qq.com";
//invoke mail() function to send email
mail($toaddress, $subject, $mailcontent, $fromaddress);
?>
<!DOCTYPE html>
<html>
<head>
<title>Bob's Auto Parts - Feedback Submitted</title>
</head>
<body>
<h1>Feedback submitted</h1>
<p>Your feedback has been sent.</p>
</body>
</html>
mail()函数:用来发送电子邮件,要使用该函数,必须在PHP安装配置中设置执行邮件发送的程序。
bool email(string to, string subject, string message,
string [additional_headers [, string additional_parameters]]);
该函数的前三个参数是必需的,分别代表发送邮件的收件地址、主题行和消息内容。
第四个参数可以用来发送任何额外的、有效的邮件header。如果需要附加多个邮件header,只要用换行符(\n\r)在字符串中将它们分开即可。
$aadditional_headers = "From: aaa@qq.com\r\n "."Reply-To: aaa@qq.com";
可选的第五个参数可以向经过设置并执行电子邮件发送操作的程序传递参数。
字符串的格式化
在使用用户输入的字符串之前,必须对他们进行整理!
字符串截断
整理字符串的第一步是清理字符串中多余的空格。
-trim():除去字符串开始位置和结束位置的空格,并将结果字符串返回。
在默认情况下,除去的字符是换行符和回车符(\n和\r)、水平和垂直制表符(\t和\x0B)、字符串结束符(\0) 和空格。除了这个默认的过滤字符串列表外,也可以在该函数的第二个参数中提供要过滤的特殊字符列表,用来代 替默认列表。
-ltrim():只从字符串的开始处(左边)除去空格。
-rtrim():只从字符串的结束处(右边)除去空格。
-chop():rtrim()的别名函数
$name = trim($_POST['name']);
$email = trim($_POST['email']);
$feedback = trim($_POST['feedback']);
格式化字符串
使用并输出用户提交数据时,需要记住并处理数据的场景。这是因为大多数接受输出的地方都会将一些字符和字符串当作特殊或控制字符和字符串,而我们并不希望用户提交的数据被解释为命令。
1.htmlspecialchars()函数–过滤输出至浏览器的字符串
该函数:将在HTML中有特殊含义的字符转换为等价的HTML实体。
注意:如果输入字符串不能满足特定编码格式,该函数将返回一个空字符串,而不会抛出任何错误 =>防止代码注入
string htmlspecialchars (string string [,int flags = ENT_COMPAT | ENT_HTML401 [, string encoding = 'UTF-8' [, bool double_encode = true]]])
参数:
第一个参数:被翻译的字符串,而函数返回值是翻译后的字符串。
第一个可选参数flags:指定了如何完成翻译。默认值是 ENT_COMPAT | ENT_HTML401。
第二个可选参数encoding:指定了转换的编码方式。从PHP5.4开始,默认编码是UTF-8。
第三个可选参数double_encode:制定了是否需要对HTML实体进行编码。默认值是执行编码。
引号的默认编码是对双引号进行编码。单引号是不会被翻译的,其行为是由flag参数控制的。
2.为其他输出形式过滤字符串
电子邮件的主要问题是电子邮件header是由“\r\n”(回撤换行符)字符串间隔。我们需要关注在邮件header使用的而用户数据是否包含这些字符。
str_replace()函数:用特定字符串替换一个完整字符串
$mailcontent = "Customer name: ".str_replace("\r\n", "", $name)."\n".
"Customer email: ".str_replace("\r\n", "", $email)."\n".
"Customer comments:\n".str_replace("\r\n", "", $feedback)."\n";
3.使用HTML格式化
HTML将忽略纯空格
nl2br()函数:将字符串作为输入参数,用HTML中的换行标记(<br />)代替字符串中的换行符(\n)。
<p>Your feedback (shown below) has been sent.</p>
<p><?php echo nl2br(htmlspecialchars($feedback)); ?></p>
注意!先使用htmlspecialchars()函数将用户输入中有特殊含义的字符转换为等价的HTML实体,再利用nl2br()函数替换换行标记。不然,nl2br()函数替换的换的换行宝宝标记将会被htmlspecialchars()函数翻译为HTML实体。
<!-- processfeedback_2.php -->
<?php
//create short variable names
$name = trim($_POST['name']);
$email = trim($_POST['email']);
$feedback = trim($_POST['feedback']);
//set up some static information
$toaddress = "aaa@qq.com";
$subject = "Feedback from web site";
$mailcontent = "Customer name: ".str_replace("\r\n", "", $name)."\n".
"Customer email: ".str_replace("\r\n", "", $email)."\n".
"Customer comments:\n".str_replace("\r\n", "", $feedback)."\n";
$fromaddress = "From: aaa@qq.com";
//invoke mail() function to send email
mail($toaddress, $subject, $mailcontent, $fromaddress);
?>
<!DOCTYPE html>
<html>
<head>
<title>Bob's Auto Parts - Feedback Submitted</title>
</head>
<body>
<h1>Feedback submitted</h1>
<p>Your feedback (shown below) has been sent.</p>
<p><?php echo nl2br(htmlspecialchars($feedback)); ?></p>
</body>
</html>
4.为打印输出而格式化字符串
print() :实现的功能与echo()相同,但具有返回值且一直返回1.
传递给这两个函数的第一个参数都是字符串格式,他们使用格式代码而不是变量来描述输出字符串的基本格式。其他的参数是用来替换格式字符串的变量。
-printf():将一个格式化的字符串输出到浏览器中
int printf(string format [, mixed args...])
-sprintf():返回一个格式化后的字符串。
string sprintf(string format [, mixed args...])
echo "Total amount of order is $total.";
等价于
printf ("Total amount of order is %s.", $total); //%s是转换规范,意思是‘用一个字符串来代替’
printf()函数的优点是可以使用更有用的转换规范。在格式化字符串中,可以使用多个转换规范。如果有n个转换规范,在格式化字符串后面就应该带有n个参数。每个转换规范都将按给出的顺序被一个重新格式化过的参数代替。
printf ("Total amount of order is %.2f (with shipping %.2f)", $total, $total_shipping);
转换规范:遵循同样的格式
%[+]['padding_character'][-][width][.precision]type
- 所有的转换规范都以%开始。如果想打印一个%,必须使用%%
- +:可选的。在默认情况下,只有负数会显示符号(-)。如果指定需要符号,则输出的正负数则分别带有+、-前缀;
- padding_character:可选的。被用来填充变量直至所指定的宽度。默认的填充字符是一个空格,如果指定另一个空格或0,就 不需要使用“'”作为前缀。对于任何其他的填充字符,必须指定“'”作为前缀;
- -:可选的。指明该域中的数据应该左对齐,而不是默认的右对齐;
- width:为被替换的变量留下多少空间(按字符计算);
- precision:必须是以一个小数点开始,指明小数点后面要显示的位数;
- type:类型码。
可以使用带序号的参数方式,意味着参数的顺序不一定要与转换规范中的顺序相同。
直接在%符号后面添加参数的位置,并且以$符号为结束。
printf ("Total amount of order is %2\$.2f (with shipping %1\$.2f)", $total_shipping, $total);
vprintf()函数和vsprintf()函数:变体函数,分别接受两个参数:格式化字符串和参数数组。
5.改变字符串中的字母大小写
使用字符串函数连接和分割字符串
函数explode()、implode()、join()
array explode(string separator, string input [, iint limit]);
$email_array = explode('@', $email);
该函数带有一个字符串(input)作为参数,并根据一个指定的分隔符字符串将输入字符串本身分割为小块,将分割后的小块返回到一个数组中。通过参数limit限制分成字符串小块的数量
implode()函数和join()函数作用相同,但与explode()函数作用相反。从数组取出元素,用第一个传入的参数字符将它们连接在一起。
$new_email = implode('@', $email_array);
函数strtok()
一次只从字符串中取出一个子字符串(称为令牌)。
string strtok(string input, string separator);
1.分割符可以是一个字符,也可以是一个字符串,但是输入字符串的分割会根据分隔符字符串中的每个字符来进行,而不是根据整个分隔字符串来进行。
2.要从字符传中得到一个令牌,需传入两个参数:一个是要进行令牌化处理的字符串,另一个是分隔符。
3.要从字符串中得到令牌序列,可以只用一个参数–分隔符。该函数会保证他自己的内部指针在字符串中的位置。如果想重置指针,可以重新将该字符串传给这个函数。
$token = strtok($feedback," ");
while ($token != ""){
echo $token."<br />";
$token = strtok(" ");
}
函数substr()
该函数允许我们访问一个字符串给定起点和终点的子字符串。通常用于需要得到某个固定格式字符串中的一部分时。
string substr(string string, int start [, int length]);
该函数将返回从string复制过来的子字符串。
$test = 'Your customer service is excellent';
#只给出了一个正数作为start参数,将得到从start位置开始到整个字符串结束位置的子字符串
substr($test, 1); #our customer service is excellent
#只给出了一个负数作为start参数,将得到从字符串结束位置往前start个位置为开始到整个字符串结束位置的子字符串。
substr($test, -9); #excellent
length参数:用于指定要返回字符的个数(正数时),或是字符串序列的结束处前length个字符(负数时)。
substr($test, 0, 4); # Your
substr($test, 5, -13); #customer service
字符串比较
字符串的排序
strcmp()、strcasecmp()、strnatcmp()函数都可用于字符串的排序。
int strcmp(string str1, string str2);
- 该函数需要两个用来比较的字符串参数。如果两个字符串相等,就返回0;如果按字典顺序str1在str2后面(大于str2)就返回一个正数,如果str1小于str2就要返回一个负数。
- 该函数区分大小写。
strcasecmp():除了不区分大小写之外,其他和strcmp()一样。
strnatcmp():和与之对应的不区分大小写的strnatcasecmp()函数将按“自然排序”比较字符串。所谓自然排序就是人们习惯的顺序进行排序。
函数strlen()
该函数会判断字符串的长度,并返回字符串的长度。=>验证字符串是否有效
使用字符串函数匹配和替换子字符串
在字符串中查找字符串
要在一个字符串中查找另一个字符串,可以使用函数strstr()、strchr()、strrchr()、stristrt()函数中的任何一个。
strchr()函数:与strstr()函数完全一样,都用于在字符串中查找一个字符串,包括查找只包含一个字符的字符串。
strstr()函数:在一个较长的字符串中查找需要匹配的字符串或字符。
string strstr(string haystack, string needle[, bool before_needle=false]);
- haystack被搜索的字符串参数;needle目标关键字字符串参数
- 如果找到了目标关键字的一个精确匹配,函数会从目标关键字前面返回被搜索的字符串,否则返回值为false。如果存在不止一个目标关键字字符串,返回的字符串从出现第一个目标关键字的位置开始。
- 如果before_needle参数设置为true,该函数将返回出现needle关键字之前的部分字符串。
$toaddress = 'aaa@qq.com'; //the default value
//Change the $toaddress if the criteria are met
if (strstr($feedbackk, 'shop')){
$toaddress = 'aaa@qq.com';
}else if (strstr($feedback, 'delivery')){
$toaddress = 'aaa@qq.com';
}else if(strstr($feedback, 'bill')){
$toaddress = 'aaa@qq.com';
}
strstr()函数的变体函数
- stristr():几乎和strstr()一样,其区别在于该函数不区分大小写
- strrchr():几乎和strstr()一样,但该函数会从最后出现needle的位置开始返回被搜索字符串。
查找子字符串的位置
strpos()和strrpos()函数操作和strstr()类似,只不过返回的是目标关键字子字符串在被搜索字符串中的位置,且运行速度更快。
int strpos(string haystack, string needle[, int offset=0]);
- 该函数返回的整数代表被搜索字符串中第一次出现目标关键字子字符串的位置。通常,第一个字符是位置0.
- needle参数:可以是任意长度的字符串,也可以是单个字符
- offset参数:可选的,用来指定被搜索字符串的开始搜索位置
$test = "Hello world";
echo strpos($test, 'o'); #返回4
echo strpos($test, 'o', 5); #返回7
strrpos():与strpos()函数几乎一样,只不过返回的是被搜索字符串在haystack中最后一次出现needle的位置。
在任何情况下,如果needle不在字符串中,strpos()和strrpos()函数都将返回false。又因为false在PHP中等于0,即字符串的第一个字符。可以使用===来测试返回值,从而避免这个问题。
$result = strpos($tetst, "H");
if ($result === false){
echo "Not found";
}else{
echo "Found at position".$result;
}
替换子字符串
查找并替换功能在PHP生成个性化文档中使用 <= 可以用字符串函数或者正则表达式来实现此功能。
替换操作最常用的字符串函数是str_replace()
mixed str_replace(mixed needle, mixed new_needle, mixed haystack[, int &count]);
- 该函数用new_needle替换haystack中所有的needle,并且返回替换后的haystack新结果。
- count参数,可选的,要执行的替换操作次数。
- 可以以数组的方式传递所有的参数,该函数可以很智能地完成替换操作。可以传递一个要被替换单词的数组,一个替换单词的数组,以及应用这些规则的目标字符串数组。这个函数将返回替换后的字符串数组。
$feedback = str_replace($offcolor, '#%!*', $feedback);
substr_replace():在给定位置中查找并替换字符串中特定的子字符串。
string substr_replace(mixed string, mixed replacement,
mixed start[, mixed length] );
- 该函数使用字符串replacement替换字符串string中的一部分。具体是那一部分取决于起始位置和可选参数length的参数值。
- start参数:替换字符串位置的开始偏移量。如果它为0或是一个整数,就是一个从字符串开始处计算的偏移量;如果它是一个负值,就是从字符串末尾开始的一个偏移量
$test = "Hello world";
$test = substr_replace($test, 'X', -1); #返回Hello worlX
- length参数:可选的。代表PHP停止替换操作的位置。如果不给出该参数值,它会从字符串start位置开始一直到字符串结束。如果length为零,替换字符串实际上会插入字符串中而不覆盖原有字符串。一个正数length表示要用新字符串替换掉的字符串长度。一个负数length表示从字符串尾部开始到第length个字符停止替换。
正则表达式
基础知识
正则表达式是一种描述文本所包含模式的方法。
在PHP中,正则表达式更像strstr()匹配,而不像相等比较,因为是咋一个字符串的某个位置(如果不指明则可能在字符传串中的任何位置)匹配另一个字符串;除此之外,还可以用特殊字符来指定表达式的元意义;还可以按特殊字符的出现来匹配。
分隔符
使用PCRE正则表达式,每个表达式必须包含在一对分隔符中。可以选择任何非字母、数字、" \ " 或空格的字符作为分隔符。目前最常用的是“ \ ”。如果要匹配 \ , 则需要使用 / 来转义。
/shop/ #匹配shop
/http:\/\// #匹配http://
字符类和类型
使用字符集合可以使得正则表达式的能力立即超过精确匹配表达式的能力。字符集合可以用于匹配属于特定类型的任何字符,事实上,它们是一种通配符。
-字符'.':作为匹配除换行符(\n)之外任何字符的通配符。通常用于匹配适用于操作系统的文件名匹配。
/.at/
-符号[]:指明字符所属的集合。任何包含在方括号中的内容都是一个字符类。注意!方括号中的表达式只匹配一个字符
/[a-z]at/ #限定第一个字母是a到z之间的字符
-字符'-':描述一个范围
/[a-zA-Z]/ #这个范围集代表大小写的任何字母
-字符'^':包含在方括号里面时,表示否
/[^a-z]/ #匹配任何不在a和z之间的字符。
!!!注意外部方括号分隔字符类,而内部方括号时字符类名称的一部分。
/[[:alpha]1-5]/ #描述包含字母字符或1到5数字的字符类
重复
- 符号*:表示这个模式可以重复出现0次或多次;
- 符号+:表示这个模式可以重复出现1次或多次;
- 符号?:表示这个模式可以出现1次或0次。
/[[:alnum:]]+/ #表示至少有一个字母字符
子表达式
使用圆括号实现将一个表达式分隔为几个子表达式
/(very )*large/ #可以用来匹配large、very large、very very large等(very出现0次或多次)
子表达式比较
使用花括号指定数字表达式来确定内容允许重复的次数。
- 可以指定一个确切的重复次数 {3}表示重复3次
- 可以指定一个重复次数的范围 {2,4}表示重复2-4次
- 可以未指定最大范围的重复模式 {2, }表示至少重复2次
/(very ){1,3}/ #表示匹配:very、very very和very very very
定位到字符串的开始或末尾
- 脱字符号^:用于正则表达式的开始,表示子字符串必须出现在被搜索字符串的开始处
- 字符$:用于正则表达式的末尾,表示子字符串必须出现在字符串的末尾
/^bob/ #在字符串开始处匹配bob
/com$/ #匹配以com结尾的字符串
/^[a-z]$/ #匹配只包含a到z之间一个字符的字符串
分支
使用符号|来表示模式选择
/com|edu|net/ #表示匹配com、edu、net
匹配特殊字符
在PHP中,必须使用单引号来引用正则表达式模式。使用双引号引用的正则表达式将带来一些不必要的复杂性。PHP还是用反斜杠来转义特殊字符。如果希望在模式中匹配一个反斜杠,必须使用两个反斜杠来表示它是一个反斜杠字符,而不是一个转义字符。
$符号也是一个由双引号引用的PHP字符串和正则表达式中的特殊字符。要使一个$字符能够在模式中匹配,必须使用 ' \\\ $'
元字符一览
元字符:所有特殊字符。
表4-6表示他们在方括号外的特殊字符的意义;表4-7表示他们在方括号里面时的意义
转义序列
- 反斜杠用来转义特殊字符
- 反斜杠用在代表非打印字符的字符前面
- 反斜杠用在特殊字符类型之前
单词字符指的是人以字母、数字、下划线。但是,如果使用与locale相关的匹配,将包含特定locale的字母,如带标音的字母。
回溯引用
回溯引用(backreference),也叫反向引用。
模式的回溯引用是通过一个反斜杠加一个数字(根据上下文不同,可以是多个数字)来表示。它用来匹配多次出现在一个字符串中的相同子表达式,而不用指定要具体匹配的内容。
/^([a-z]+) \1 black sheep/
# \1是对前面匹配子表达式的回溯引用,也就是([a-z]+)。
# 将匹配‘baa baa black sheep’,但不会匹配‘blah baa black sheep’
原因:回溯引用是指‘找到匹配前面子表达式的内容,并且与该内容完全相同的内容再次出现在后续内容’。如果要匹配多个子表达式,应该按照\后面的数字的顺序来匹配,也就是说,与子表达式匹配的内容按照该数字表示的顺序出现。
断言
断言是用来在目标字符串的当前匹配位置进行的一种测试和检查,但这种测试并不占用目标字符串,也不会移动模式在目标字符串中的当前匹配位置。
单词边界:单词字符与非单词字符连接的位置
断言的开始和结束类似于^和$特殊字符,但PHP的某些位置不能改变\A、\z、\Z的行为
\G类似于开始断言,但是它可以与一些正则表达式函数同时使用在从特定偏移位置开始匹配的场景
用正则表达式查找子字符串
最简单的函数是preg_match()函数
int preg_match(string pattern, string subject[, array matches[, int flag=0[, int offset=0]]])
- 该函数将在subject字符串中搜索匹配pattern正则表达式的子字符串。如果找到与pattern的子表达式相匹配的子字符串,将其保存在matches数组中,每个数组元素对应一个子表达式的匹配。
- flags参数的唯一值是PREG_OFFSET_CAPTURE。如果设置了该参数,matches数组会是不同的格式。数组组每个元素将由匹配的子表达式数组及在subject字符串中的偏移量组成
- offset参数:用来指定从指定偏移位置开始查询subject字符串
- 如果找到匹配的,preg_match()函数返回1;如果没找到,返回0;如果出现匹配错误,返回FALSE。就意味着必须使用===检查返回值,避免将0与FALSE结果混淆。
#在订单处理脚本添加如下代码,使用正则表达式
if (preg_match('/^[a-zA-Z0-9_\-\.]aaa@qq.com[a-zA-Z0-9\-\.]+$/',$email) === 0){
echo "<p>That is not a valid email address.</p>".
"<p>Please return to the previous page and try again.</p>";
exit;
}
$toaddress = 'aaa@qq.com'; //the default value
if (preg_match('/shop|customer service|retail/', $feedback)){
$toaddress = 'aaa@qq.com';
}
用正则表达式替换子字符串
mixed preg_replace(string pattern, string replacement, string subject[, int limit=-1[, int &count]])
- 该函数在subject字符串中查找匹配正则表达式pattern的字符串,并且用字符串replacement来替换
- limit参数:指定要执行替换操作的次数。默认是-1,意味着没有限制
- count参数:被赋值执行的替换操作次数
用正则表达式分割字符串
array preg_split(string pattern, string subject[, int limit=-1[, int flag=0]]);
- 该函数将subject字符串分割成复合正则表达式的子字符串数组。
- limit参数:限制子字符串数组的元素个数。默认是-1,意味着没有限制
- flag参数:接受以下常量值,可以通过位操作符进行组合
PREG_SPLIT_NO_EMPTY:表示只返回非空数据
PREG_SPLIT_DELIM_CAPTURE:表示分隔符也会被返回
PREG_SPLIT_OFFSET_CAPTURE:表示返回咩个子字符串元素出现在原字符串的位置。
$address = 'aaa@qq.com';
$arr = preg_split('/\.|@/',$address);
while (list($key, $value) = each ($arr)){
echo '<br />'.$value;
}
#被分成3部分:逐行打印输出:
username
example
com
一般而言,正则表达式哈桑农户运行效率低于字符串函数!!!
上一篇: Dubbo 配置注意事项
下一篇: webdriver 配置注意事项