- PHP從入門到精通(微視頻精編版)
- 明日科技
- 7824字
- 2020-11-23 14:41:14
第4章 字符串操作與正則表達式
(視頻講解:1小時56分鐘)
在Web編程中,字符串總是會被大量地生成和處理。正確地使用和處理字符串,對于PHP程序員來說越來越重要。本章從最簡單的字符串定義一直引導讀者到復雜的正則表達式,希望廣大讀者能夠通過本章的學習,了解和掌握PHP字符串,達到舉一反三的目的,為了解和學習其他的字符串處理技術奠定良好的基礎。
學習摘要:
字符串的定義
字符串操作
正則表達式
正則表達式應用
4.1 字符串的定義方法

視頻講解
字符串,顧名思義,就是將一堆字符串聯在一起。字符串最簡單的定義方法是使用英文單引號('')或雙引號("")包含字符。另外,還可以使用定界符指定字符串。
4.1.1 使用單引號或雙引號定義字符串
字符串通常以串的整體作為操作對象,一般用雙引號或者單引號標識一個字符串。單引號和雙引號在使用上有一定區別。
下面分別使用雙引號和單引號來定義一個字符串。例如:

運行結果如下:

從上面的結果中可以看出,對于定義的普通字符串看不出兩者之間的區別。而通過對變量的處理,即可輕松地理解兩者之間的區別。例如:

運行結果如下:

從以上代碼中可以看出,雙引號中的內容是經過PHP的語法分析器解析過的,任何變量在雙引號中都會被轉換為它的值進行輸出顯示;而單引號的內容是“所見即所得”的,無論有無變量,都被當作普通字符串進行原樣輸出。
說明
單引號字符串和雙引號字符串在PHP中的處理是不相同的。雙引號字符串中的內容可以被解釋并且被替換,而單引號字符串中的內容則被作為普通字符進行處理。
4.1.2 使用定界符定義字符串
定界符(<<<)是從PHP 4.0開始支持的。定界符用于定義格式化的大文本,格式化是指文本中的格式將被保留,所以文本中不需要使用轉義字符。在使用時后接一個標識符,然后是字符串,最后是同樣的標識符結束字符串。定界符的語法格式如下:

其中str為指定的標識符,標識符讀者可以自己設定,切記要前后保持一致。
使用定界符定義字符串的方式與雙引號沒什么區別,包含的變量也被替換成實際數值,例如:

運行結果如下:

注意
結束標識符必須單獨另起一行,并且不允許有空格。在標識符前后有其他符號或字符,也會發生錯誤。
4.2 字符串操作

視頻講解
字符串的操作在PHP編程中占有重要的地位,幾乎所有的輸入與輸出都用到字符串。尤其是在PHP項目開發過程中,為了實現某項功能,經常需要對某些字符串進行特殊處理,如獲取字符串的長度、截取字符串、替換字符串等。本節將對PHP常用的字符串操作技術進行詳細講解,并通過具體的實例加深對字符串函數的理解。
4.2.1 去除字符串首尾空格和特殊字符
用戶在輸入數據時,可能會無意中輸入多余的空格,或在一些情況下,字符串前后不允許出現空格和特殊字符,此時就需要去除字符串中的空格和特殊字符。例如,圖4.1中“HELLO”這個字符串前后都有一個空格。可以使用PHP中提供的trim()函數去除字符串左右兩邊的空格和特殊字符,也可以使用ltrim()函數去除字符串左邊的空格和特殊字符,或使用rtrim()函數去除字符串右邊的空格和特殊字符。

圖4.1 前后包含空格的字符串
1.trim()函數
trim()函數用于去除字符串首尾處的空白字符(或者其他字符)。語法格式如下:

參數及返回值說明如下。
str:操作的字符串。
charlist:為可選參數,一般要列出所有希望過濾的字符,也可以使用“..”列出一個字符范圍。如果不設置該參數,則所有的可選字符都將被刪除。trim()如果不指定charlist參數,trim()函數將去除表4.1中的字符。
返回值:過濾后的字符串。
表4.1 不指定charlist參數trim()函數去除的字符

注意
除了以上默認的過濾字符列表外,也可以在charlist參數中提供要過濾的特殊字符。
【例4.01】 明日學院網站中有搜索課程和社區的功能,當在輸入框中輸入關鍵詞并單擊“搜索”按鈕時,程序會先處理用戶輸入的關鍵詞,將關鍵詞左右的空格去除。使用trim()函數實現該功能,代碼如下:(實例位置:資源包\源碼\04\4.01)

運行結果如圖4.2所示。

圖4.2 trim()去除左右空格
2.ltrim()函數
ltrim()函數用于去除字符串左邊的空格或者指定字符串。ltrim()函數參數與trim()函數相同。語法格式如下:

例如,使用ltrim()函數去除字符串左邊的空格及特殊字符(:@_@,代碼如下:

運行結果如下:

3.rtrim()函數
rtrim()函數用于去除字符串右邊的空格或指定字符。語法格式如下:

例如,使用rtrim()函數去除字符串右邊的空格及特殊字符@_@:),代碼如下:

運行結果如下:

4.2.2 獲取字符串的長度
在PHP中常見的計算字符串長度的函數有strlen()和mb_strlen()。當字符全是英文字符時,兩者功能是一樣的。但是,當字符串中包含中文時,所占字節有所不同。先來了解一下英文和中文所占字節情況。
數字、英文、小數點、下畫線和空格占1字節,一個漢字可能會占2~4字節,具體占幾字節取決于采用的是什么編碼。漢字在GBK/GB 2312編碼中占2字節,在UTF-8/Unicode中一般占用3字節(或2~4字節)。本書中所有文件均使用UTF-8編碼,即一個漢字占3字節,如圖4.3所示。

圖4.3 漢字和英文所占字節個數
下面講解如何使用strlen()和mb_strlen()函數獲取指定字符串的長度。
1.strlen()函數
strlen()函數主要用于獲取指定字符串的長度。語法格式如下:

參數及返回值說明如下。
str:需要計算長度的字符串。
返回值:成功則返回字符串str的長度;如果str為空,則返回0。
例如,使用strlen()函數來獲取指定字符串的長度,代碼如下:

在上述代碼中“明日學院官方網站:”均為中文字符,每個占3字節,共占用27字節。“www. mingrisoft.com”均為英文字符,每個占1字節,共占用18字節。運行結果如下:

2.mb_strlen()函數
由于strlen()無法正確處理中文字符串,它得到的只是字符串所占的字節數,可以采用mb_strlen()函數較好地解決這個問題。
mb_strlen()函數主要用于獲取指定字符串的長度。語法格式如下:

參數及返回值說明如下。
str:需要計算長度的字符串。
encoding:字符編碼。如果省略,則使用內部字符編碼。
返回值:返回具有encoding編碼的字符串$str包含的字符數。多字節的字符被計為1。如果給定的encoding無效則返回false。
mb_strlen()函數的用法和strlen()類似,只不過它有第二個可選參數用于指定字符編碼。例如,得到UTF-8的字符串$str長度,可以用mb_strlen($str,'UTF-8')。如果省略第二個參數,則會使用PHP的內部編碼。內部編碼可以通過mb_internal_encoding()函數得到。
注意
mb_strlen()并不是PHP核心函數,使用前需要確保在php.ini中加載了php_mbstring.dll,即確保extension=php_mbstring.dll這一行存在并且沒有被注釋掉,否則會出現未定義函數的問題。
【例4.02】 明日學院網站注冊頁面中,用戶注冊時輸入的用戶名必須為3~18位中英文字符,既可以是全中文,也可以是全英文或者中英文混合。使用mr_strlen()函數實現該功能,代碼如下:(實例位置:資源包\源碼\04\4.02)

運行結果如圖4.4所示。

圖4.4 判斷用戶名是否滿足條件
4.2.3 截取字符串
PHP對字符串截取可以采用內置函數substr()和mb_substr()實現。通常使用substr()函數截取英文字符,mb_substr()函數截取中文或中英文混合字符。
1.substr()函數
substr()函數的語法格式如下:

參數及返回值說明如下。
str:指定字符串對象。
start:指定開始截取字符串的位置。如果參數start為負數,則從字符串的末尾開始截取。
length:可選參數,指定截取字符的個數,如果length為負數,則表示取到倒數第length個字符。
返回值:返回提取的子字符串,或者在失敗時返回false。
注意
本函數中,參數start的指定位置是從0開始計算的,即字符串中的第一個字符表示為0,如圖4.5所示。

圖4.5 start開始位置
使用substr()函數截取字符串中指定長度的字符,代碼如下:

運行結果如下:

由于在UTF-8編碼下,一個漢字占3字節,所以在使用substr()函數時,可能出現截取漢字不完整的情況。例如,使用substr()函數截取字符串“Hi明日科技”,代碼如下:

上述代碼中,start為0,length為7,即從第一個位置開始,截取7字節,如圖4.6所示。由于在第7個字符位置,漢字“日”沒有被截取完成,將會出現漢字亂碼,運行結果如圖4.7所示。

圖4.6 substr()函數截取

圖4.7 substr()函數截取漢字亂碼
2.mb_substr()函數
針對substr()函數截取漢字亂碼問題,可以使用mb_substr()函數來解決。mb_substr()函數語法格式如下:

參數及返回值說明如下。
str:從該string中提取子字符串。
start:str中要截取的第一個字符的位置。
length:可選參數,指定截取字符的個數,如果length為負數,則表示取到倒數第length個字符。
encoding:字符編碼。如果省略,則使用內部字符編碼。
返回值:根據start和length參數返回str中指定的部分。
【例4.03】 在明日學院網站“最新動態”專欄中,顯示所有最新課程標題的列表。為了保持整個頁面的合理布局,需要對一些超長標題進行部分顯示,使用mb_substr()函數截取超長文本的部分字符串,剩余的部分用“…”代替。代碼如下:(實例位置:資源包\源碼\04\4.03)

運行結果如圖4.8所示。

圖4.8 mb_substr()函數截取字符串
4.2.4 檢索字符串
在PHP中,提供了很多應用于字符串查找的函數,最常用的有strstr()函數和strpos()函數。
1.strstr()函數
獲取一個指定字符串在另一個字符串中首次出現的位置到后者末尾的子字符串。語法格式如下:

參數及返回值說明如下。
haystack:指定從該字符串中進行搜索。
needle:指定搜索的對象。如果needle不是一個字符串,那么它將被轉化為整型并且作為字符的序號來使用。
before_needle:可選參數,默認為false。若為true,strstr()將返回needle在haystack中的位置之前的部分。
返回值:返回haystack字符串從needle第一次出現的位置開始到haystack結尾的字符串。
例如,獲取“Hi明日科技”字符串中“明日”以后的內容。代碼如下:

strstr()函數實現方式如圖4.9所示,運行結果如下:

圖4.9 strstr()函數實現方式

注意
本函數區分字母的大小寫,如不區分大小寫,可以使用stristr()函數。
【例4.04】 使用strstr()函數,根據郵箱地址,獲取郵箱用戶名和服務器名,代碼如下:(實例位置:資源包\源碼\04\4.04)

運行結果如圖4.10所示。

圖4.10 strstr()函數獲取用戶名和服務器名
說明
strrchr()函數與其正好相反,該函數是從字符串倒序的位置開始檢索子字符串的。
2.strpos()函數
查找字符串首次出現的位置,返回首次出現的數字位置。語法格式如下:

參數及返回值說明如下。
haystack:必要參數,指定從該字符串中進行搜索。
needle:必要參數,指定搜索的對象。如果needle不是一個字符串,那么它將被轉化為整型并且作為字符的序號來使用。
offset:可選參數,默認為0。如果提供了此參數,搜索會從字符串該字符數的起始位置開始統計。
返回值:返回needle存在于haystack字符串起始的位置。同時注意字符串位置是從0開始,而不是從1開始的。如果沒找到needle,將返回false。
注意
本函數區分字母的大小寫,如不區分大小寫,可以使用stripos()函數。
例如,獲取“Hi明日科技”字符串中“明日”以后的內容。代碼如下:

strpos()函數實現方式如圖4.11所示,運行結果如下:

圖4.11 strpos()函數實現方式

說明
strrpos()函數與其正好相反,該函數是計算指定字符串在目標字符串中最后一次出現的位置。strrpos()函數也區分大小寫,如不區分大小寫,可以使用strripos()函數。
4.2.5 替換字符串
通過字符串的替換技術可以實現對指定字符串中的指定字符進行替換。字符串的替換技術可以通過str_replace()函數和substr_replace()函數實現。
1.str_replace()函數
使用新的子字符串替換原始字符串中被指定要替換的字符串。語法格式如下:

將所有在參數subject中出現的參數search以參數replace取代,參數&count表示取代字符串執行的次數。本函數區分大小寫。
參數及返回值說明如下。
search:必要參數,要搜索的值,可以使用數組來提供多個值。
replace:必要參數,指定替換的值。
subject:必要參數,要被搜索和替換的字符串或數組。
count:可選參數,如果被指定,它的值將被設置為替換發生的次數。
返回值:替換后的字符串或者數組。
例如,將文本中的指定字符串“某某”替換為“**”,并且輸出替換后的結果,代碼如下:

運行結果如下:

注意
str_replace()函數在執行替換操作時區分大小寫,如果不需要對大小寫加以區分,可以使用str_ireplace()函數。
2.substr_replace()函數
對指定字符串中的部分字符串進行替換。語法格式如下:

參數及返回值說明如下。
string:指定要操作的原始字符串,可以是字符串或數組。
replacement:指定替換后的新字符串。
start:指定替換字符串開始的位置。正數表示替換從字符串的第start位置開始;負數表示替換從字符串的倒數第start位置開始;0表示替換從字符串中的第一個字符開始。
length:可選參數,指定返回的字符串長度。默認值是整個字符串。正數表示被替換的子字符串的長度;負數表示待替換的子字符串結尾處距離字符串末端的字符個數;0表示將replacement插入到string的start位置處。
返回值:返回結果字符串。如果string是個數組,那么也將返回一個數組。
注意
如果參數start設置為負數,而參數length數值小于或等于start數值,那么length的值自動為0。
【例4.05】 明日學院網站舉辦抽獎活動,活動結束后將獲獎用戶姓名和手機號公布在網站上,為保護用戶隱私,將獲獎用戶的手機號中間4位用“****”替換,代碼如下:(實例位置:資源包\源碼\04\4.05)

運行結果如圖4.12所示。

圖4.12 substr_replace()函數替換手機號
4.2.6 分割、合成字符串
在PHP中,提供了分割和合成字符串的函數,它們都與數組相關。數組就是一組數據的集合,把一系列數據組織起來,形成一個可操作的整體。數組的知識會在第5章講解,先來了解一下如何分割和合成字符串。
1.分割字符串
explode()函數按照指定的規則對一個字符串進行分割,返回值為數組。語法格式如下:

參數及返回值說明如下。
delimiter:邊界上的分隔符。
string:指定將要被進行分割的字符串。
limit:可選參數,如果設置了limit,則返回的數組包含最多limit個元素,而最后的元素將包含$string的剩余部分。
返回值:該函數返回由字符串組成的數組,每個元素都是string的一個子串,它們被字符串delimiter作為邊界點分割出來。
2.合成字符串
implode()函數可以將數組的內容組合成一個新字符串。語法格式如下:

參數及返回值說明如下。
glue:指定分隔符。
pieces:指定要被合并的數組。
返回值:返回一個字符串,其內容為由glue分割開的數組的值。
例如,使用implode()函數將數組中的內容以@為分隔符進行連接,從而組合成一個新的字符串,代碼如下:

運行結果如下:

說明
implode()函數和explode()函數是兩個相對的函數,一個用于合成,一個用于分割。
4.3 正則表達式

視頻講解
4.3.1 正則表達式簡介
在編寫處理字符串的程序或網頁時,經常會有查找符合某些復雜規則的字符串的需要。正則表達式就是用于描述這些規則的工具。換句話說,正則表達式就是記錄文本規則的代碼。對于接觸過DOS的讀者來說,如果想匹配當前文件夾下所有的文本文件,可以輸入dir *.txt命令,按Enter鍵后所有.txt文件將會被列出來。這里的*.txt即可理解為一個簡單的正則表達式。
4.3.2 行定位符
行定位符用來描述字串的邊界。“^”表示行的開始;“$”表示行的結尾。例如:

該表達式表示要匹配字串tm的開始位置是行頭,如tm equal Tomorrow Moon就可以匹配,而Tomorrow Moon equal tm則不匹配。但如果使用:

后者可以匹配而前者不能匹配。如果要匹配的字串可以出現在字符串的任意部分,那么可以直接寫成:

這樣兩個字符串就都可以匹配了。
4.3.3 元字符
現在我們已經知道幾個很有用的元字符了,如“^”“$”。正則表達式中還有更多的元字符,下面來看看更多的例子:

匹配以字母mr開頭的單詞,先是從某個單詞開始處(\b),然后匹配字母mr,接著是任意數量的字母或數字(\w*),最后單詞結束處(\b)。該表達式可以匹配mrsoft、mrbook、mr123456等。更多常用元字符如表4.2所示。
表4.2 常用元字符

4.3.4 限定符
在上面的例子中,使用(\w*)匹配任意數量的字母或數字。如果想匹配特定數量的數字,該如何表示呢?正則表達式提供了限定符(指定數量的字符)來實現該功能。如匹配8位QQ號可用如下表示式:

常用的限定符如表4.3所示。
表4.3 常用限定符

4.3.5 字符類
正則表達式查找數字和字母是很簡單的,因為已經有了對應這些字符集合的元字符(如\d和\w),但是如果要匹配沒有預定義元字符的字符集合(如元音字母a,e,i,o,u),應該怎么辦?
很簡單,只需要在方括號中列出它們即可,像[aeiou]就匹配任何一個英文元音字母,[.?!]匹配標點符號(.或?或!)。也可以輕松地指定一個字符范圍,像[0-9]代表的含意與\d就是完全一致的:一位數字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考慮英文的話)。
4.3.6 排除字符
上面的例子是匹配符合命名規則的變量。現在反過來,匹配不符合命名規則的變量,正則表達式提供了“^”字符。這個元字符在4.3.2節中出現過,表示行的開始。而這里將會放到方括號中,表示排除的意思。例如:

該表達式匹配的就是不以字母開頭的變量名。
4.3.7 選擇字符
試想一下,如何匹配身份證號碼?首先需要了解一下身份證號碼的規則。身份證號碼長度為15位或者18位。如果為15位時,則全為數字;如果為18位時,前17位為數字,最后一位是校驗位,可能為數字或字符X。
在上面的描述中,包含著條件選擇的邏輯,這就需要使用選擇字符(|)來實現。該字符可以理解為“或”,匹配身份證的表達式可以寫成如下方式:

該表達式的意思是匹配15位數字,或者18位數字,或者17位數字和最后一位。最后一位可以是數字或者是X或者是x。
4.3.8 轉義字符
正則表達式中的轉義字符(\)和PHP中的大同小異,都是將特殊字符(如“.”“?”“\”等)變為普通的字符。舉一個IP地址的實例,用正則表達式匹配諸如127.0.0.1這樣格式的IP地址。如果直接使用點字符,格式如下:

這顯然不對,因為“.”可以匹配一個任意字符。這時,不僅是127.0.0.1這樣的IP,連127101011這樣的字串也會被匹配出來。所以在使用“.”時,需要使用轉義字符(\)。修改后上面的正則表達式格式如下:

說明
括號在正則表達式中也算是一個元字符。
4.3.9 分組
通過4.3.8節中的例子,相信讀者已經對小括號的作用有了一定的了解。小括號字符的第一個作用就是可以改變限定符的作用范圍,如“|”“*”“^”等。來看下面的一個表達式:

這個表達式的意思是匹配單詞thirth或fourth,如果不使用小括號,那么就變成了匹配單詞thir和fourth了。
小括號的第二個作用是分組,也就是子表達式。如(\.[0-9]{1,3}){3},就是對分組(\.[0-9]{1,3})進行重復操作。
4.4 正則表達式在PHP中的應用

視頻講解
PHP中提供了兩套支持正則表達式的函數庫,即PCRE函數庫和POSIX函數庫。PCRE函數庫在執行效率上要略優于POSIX函數庫,所以這里只講解PCRE函數庫中的函數。PCRE函數庫中常用函數如表4.4所示。
表4.4 PCRE函數庫中常用函數

下面講解如何使用PHP中最常用的preg_match()函數。
preg_match()函數用于執行匹配正則表達式,函數語法如下:

參數及返回值說明如下。
pattern:要搜索的模式,字符串類型。
subject:輸入字符串。
matches:可選參數,如果提供了參數matches,它將被填充為搜索結果。$matches[0]將包含完整模式匹配到的文本,$matches[1]將包含第一個捕獲子組匹配到的文本,以此類推。
返回值:返回pattern的匹配次數。它的值將是0次(不匹配)或1次,因為preg_match()在第一次匹配后將會停止搜索。如果發生錯誤preg_match()返回false。
【例4.06】 在明日學院網站注冊頁面中,需要對用戶輸入的手機號碼格式進行檢測,以避免用戶手誤導致注冊失敗。使用preg_match()函數實現該功能,代碼如下:(實例位置:資源包\源碼\04\4.06)

運行結果如圖4.13所示。

圖4.13 preg_match()函數檢測手機號碼格式
多學兩招
preg_match_all()函數用于執行一個全局正則表達式匹配。它會一直搜索subject直到到達結尾。
4.5 小結
本章主要對常用的字符串操作技術進行了詳細講解,其中去除字符串首尾空格、獲取字符串的長度、截取字符串和字符串的查找與替換等都是需要重點掌握的技術。此外,還介紹了正則表達式的基礎知識。這些內容也是作為一個PHP程序員必須熟悉和掌握的知識。相信通過本章的學習,讀者能夠舉一反三,對所學知識靈活運用,從而開發實用的PHP程序。
4.6 實戰
4.6.1 “…”代替多余字符
實例位置:資源包\源碼\04\實戰\01
模擬淘寶詳情頁,當商品名稱多于30字時,截取前20個字符,剩余用“…”代替。運行結果如圖4.14所示。

圖4.14 實例運行結果
4.6.2 判斷車牌號歸屬地
實例位置:資源包\源碼\04\實戰\02
將“津A·12345”“滬A·23456”“京A·34567”這3張號牌放到數組中,然后在遍歷數組的過程中完成對每張號牌歸屬地的判斷,運行結果如圖4.15所示。

圖4.15 實例運行結果
4.6.3 檢測郵箱格式
實例位置:資源包\源碼\04\實戰\03
模擬明日學院網站登錄頁面,實現檢測郵箱格式的功能,運行結果如圖4.16所示。

圖4.16 實例運行結果
- Python自動化運維快速入門
- HDInsight Essentials(Second Edition)
- Learning JavaScript Data Structures and Algorithms
- MongoDB,Express,Angular,and Node.js Fundamentals
- INSTANT Yii 1.1 Application Development Starter
- Python Interviews
- MySQL程序員面試筆試寶典
- FFmpeg開發實戰:從零基礎到短視頻上線
- Java程序設計基礎(第6版)
- Deep Learning for Natural Language Processing
- Hands-On Dependency Injection in Go
- 你好!Python
- 虛擬現實:引領未來的人機交互革命
- 深入實踐C++模板編程
- CISSP in 21 Days(Second Edition)