劉亦菲生日當(dāng)天,引發(fā)了我對正則的思考

前兩天從網(wǎng)上采集到一條短視頻數(shù)據(jù)(刷短視頻),發(fā)現(xiàn)六公主連排5部劉亦菲主演的電影!甚是震驚,太有牌面了,看了一下日子是8月25號,嗷,原來當(dāng)天是劉亦菲的生日。巧了,正好也是我家柴犬旺財?shù)?歲生日
。
言歸正傳,我們看到這條數(shù)據(jù)的
標(biāo)題:#劉亦菲35歲生日獲央視獨寵# 神仙姐姐生日快樂!
為了分析數(shù)據(jù),我們需要獲取數(shù)據(jù)中所提到的話題#劉亦菲35歲生日獲央視獨寵#。提問:你能想到幾種實現(xiàn)方式呢?歡迎評論區(qū)留言。
正則
想必細心看標(biāo)題的朋友一定會猜到本文的主人公——正則,這玩意優(yōu)點是寫起來快,但缺點也顯而易見,性能差,跟批處理一個德性,反人類的難記,長時間不用,每次都要重新學(xué)習(xí),日常開發(fā)中也就偶爾寫工具用一下。因此,我們只需要把常用的正則理解透就可以了,不要有心理包袱,看完本文,大部分的正則使用場景就可以活學(xué)活用。
場景一:匹配兩個#之間的字符串
現(xiàn)在我們把需求轉(zhuǎn)換成實現(xiàn)思路,想要獲取上述數(shù)據(jù)中的話題,其實就是匹配兩個#之間的文本內(nèi)容,show code:
正則表達式:#.*?#
????public?static?void?main(String[]?args)?{
????????String?title?=?"#劉亦菲35歲生日獲央視獨寵#?神仙姐姐生日快樂!";
????????Pattern?p?=?Pattern.compile("(#.*?#)");
????????Matcher?m?=?p.matcher(title);
????????while?(m.find())?{
????????????String?group?=?m.group(0);
????????????System.out.println("話題:"?+?group);
????????}
????}
輸出
話題:#劉亦菲35歲生日獲央視獨寵#
可以看出,輸出的結(jié)果就是該條數(shù)據(jù)的話題,給大家分析一下這個正則表達式:.表示任意字符,?平時表示匹配0個或者多個,此時它表示不貪婪,那什么是貪婪呢?
說到貪婪,那就不得不提這兩個限定符:* 和 + ,它們兩個就是貪婪的!*表示匹配0個或者多個,+表示匹配至少一個,可以發(fā)現(xiàn)它們的共性:都會盡可能匹配更多。但,只要緊跟在它們的后面加上一個 ? ,讓他們捫心自問,就可以實現(xiàn)非貪婪,即最小匹配。比如,我們在標(biāo)題上再加一個#,此時標(biāo)題變?yōu)?code style="font-size:14px;color:rgb(30,107,184);background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;">#劉亦菲35歲生日獲央視獨寵## 神仙姐姐生日快樂!,然后正則表達式我們不使用?,此時,運行代碼后輸出結(jié)果為:
話題:#劉亦菲35歲生日獲央視獨寵##
比較兩次的執(zhí)行結(jié)果,我們會發(fā)現(xiàn)輸出結(jié)果多了一#,這樣就很貪婪,違背了我們的初衷,這就是?的妙用。
場景二:只匹配#開頭的字符串
我們知道不同平臺的話題格式是不一樣的,比如抖音,它的話題形式就與微博不同,只是#開頭,并沒有成對的#與其呼應(yīng):
標(biāo)題:#劉亦菲35歲生日獲央視獨寵 神仙姐姐生日快樂!
如果是這種形式的話題,愛動腦筋的朋友就會發(fā)現(xiàn)無非就是將后面的#變?yōu)橐粋€空格或者多個空格唄。沒錯,我們可以使用
正則表達式:#.*?\\s+
????public?static?void?main(String[]?args)?{
????????String?title?=?"#劉亦菲35歲生日獲央視獨寵??神仙姐姐生日快樂!";
????????Pattern?p?=?Pattern.compile("(#.*?\\s+)");
????????Matcher?m?=?p.matcher(title);
????????while?(m.find())?{
????????????String?group?=?m.group(0);
????????????System.out.println("話題:"?+?group);
????????}
????}
輸出
話題:#劉亦菲35歲生日獲央視獨寵?
Tips:\s 表示匹配所有空白符,它不僅僅可以匹配空格,還可以匹配換行等空白字符,如果再加上+,組合起來就表示甭管幾個空白字符,統(tǒng)統(tǒng)all in。
不過,不要高興得太早,心細的小明還發(fā)現(xiàn)話題可能會存在文末的情況:
標(biāo)題:神仙姐姐生日快樂!#劉亦菲35歲生日獲央視獨寵
此時是沒有空白字符結(jié)束的,上面的正則就不滿足這種情況。那如何是好?小明當(dāng)時就想到了兩個方案:
- 方案一:不管話題在不在文末,我們在匹配之前全部給標(biāo)題追加一個空白字符,這樣就可以人為干預(yù),巧妙地避開了這種情況,曲線救國,便于正則匹配
-
方案二:使用正則表達式
#.*?$
Tips:方案二中的$ 是用來匹配輸入字符串的結(jié)尾位置,組合起來就表示匹配#開頭,一直到句末的話題。
進階
前面兩種場景我們雖然獲取到了兩個#之間或者#開頭的內(nèi)容,實現(xiàn)了需求,但是匹配的結(jié)果還是會帶上#,貪婪的小明不滿足現(xiàn)狀(產(chǎn)品強制要求),可不可以不帶呢?當(dāng)然可以了!小明又想到了兩個方案:
-
方案一:得到匹配的話題后,再二次文本處理去掉
# -
方案二:使用正則表達式
?<=和?=一步到位,直接去除#
使用方法
-
(?<=exp2)exp1:表示匹配exp2后面的exp1 -
exp1(?=exp2):表示匹配exp2前面的exp1那結(jié)合以上我們實際使用的所有場景,最終這個理想的正則表達式就正式出爐(好熱):((?<=#).*?(?=#|\s+))
反應(yīng)慢的朋友,可以慢點理解,我們先運行試一下(不自信):
????public?static?void?main(String[]?args)?{
????????String?title?=?"#劉亦菲#?#神仙姐姐?#生日快樂#?#劉亦菲35歲生日獲央視獨寵";
????????Pattern?p?=?Pattern.compile("((?<=#).*?(?=#|\\s+|$))");
????????Matcher?m?=?p.matcher(title);
????????while?(m.find())?{
????????????String?group?=?m.group(0);
????????????System.out.println("話題:"?+?group);
????????}
????}
輸出
話題:劉亦菲
話題:
話題:神仙姐姐
話題:生日快樂
話題:
話題:劉亦菲35歲生日獲央視獨寵
Tips:正則表達式中的|表示或,即多項之間的一個選擇,就像今天你看完本文,感覺不錯的話,必須做出(關(guān)注|點贊|星標(biāo))其中的一個選擇!
從代碼的輸出結(jié)果我們可以看出,目前的正則是經(jīng)得住實際考驗的。但是唯一美中不足的是,會有空字符串的情況出現(xiàn)(產(chǎn)品不同意)。這該如何是好?
目前小明的解決方案是,拿到匹配結(jié)果時,過濾掉空字符串。能解決問題的辦法就是好辦法。
不過,肯定有更完美的表達式可以實現(xiàn)這個需求,此處拋磚引玉,期待你在評論區(qū)分享!
常用的正則表達式分享
- 微信號(并不能幫你要到男神|女神的微信號)
^[a-zA-Z][a-zA-Z\d_-]{5,19}$
歡迎補充,未完待續(xù)……
