正則之反向引用


前言

某日在逛stackoverflow時,發現側邊欄的Hot Network Questions里有一例codegolf的問題Does it repeat?

挑戰

好奇之下點入觀看,該題主的挑戰如下:

當一條字符串中含有2(組/個)連續的字符時,該字符串可以稱之為“連續的字符串”。
例:2034384538452可以成為“連續的字符串”,因為其含有2次連續的3845。
請找出能夠判斷“連續的字符串”的方法,輸入可以用字符串或數組,輸入不能為空,並且字符串長度必須大於等於1。
題主使用1與0來區分true和false,挑戰者也可以使用其他不同的值來區分true/false。

abcab -> 0
bdefdefg -> 1
Hello, World! -> 1
pp.pp/pp -> 1
q -> 0
21020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120210121020121012021012102012021020121012021012102012101202102012021012102012021020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120210121020120210201210120210201202101210201210120210121020120210201210120210121020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120 -> 0

解法

所有答者中,大部分常用編程語言的答者都使用正則進行判斷,例如:
PHP的解法

<?=preg_match('#(.+)\1#',$argn);

Python的解法

import re
re.compile(r'(.+)\1').search

JavaScript的解法

s=>/(.+)\1/.test(s)

Java的解法

a->a.matches(".*(.+)\\1.*")

雖然也有使用循環對比來解答的,但這不是我的關注點。

所有正則的解法中,歸根結底就是6個字符(.+)\1
.+()的意思好理解,畢竟是常用的。\1雖然能猜到用途,但是無論如何想不起來是干啥的,進入查詢模式。

反向引用(backreference)

根據揭開正則表達式的神秘面紗一文,發現原來正則除了貪婪和非貪婪外還有名為“反向引用”的高級規則。

表達式在匹配時,表達式引擎會將小括號 “( )” 包含的表達式所匹配到的字符串記錄下來。在獲取匹配結果的時候,小括號包含的表達式所匹配到的字符串可以單獨獲取。

“\1” 引用第1對括號內匹配到的字符串,”\2” 引用第2對括號內匹配到的字符串……以此類推。
如果一對括號內包含另一對括號,則外層的括號先排序號。換句話說,哪一對的左括號 “(“ 在前,那這一對為先。

在正則(.+)\1中,\1等於(.+)中匹配到的值,也就是連續2次相同的值。

嘗試

使用Python進行快速嘗試

def fa(regex,subject):
return re.findall(regex,subject);

匹配出3連的連續字符串

fa(r'(.+)\1\1','d123123123e');
#['123']
 
fa(r'(.+)\1\1','d112233e');
#[]
 
#
fa(r'((.+))\1\2','d123123123e');
#['123']

匹配出html標簽內的文字

fa(r'.*<(.+).*?>(.*)<\/\1>.*','asdwas<td>ssd</td>sdasdd');
#[('td', 'ssd')]
 
fa(r'.*<(.+).*?(?:href="(.*?)".*?)?>(.*)<\/\1>.*','asdwas<a href="/a/b">find more</a>sda');
#[('a', '/a/b','find more')]
 
fa(r'.*<(.+).*?(?:href="(.*?)".*?)?>(.*)<\/\1>.*','asdwas<a title="c" href="/a/b" class="on">find more</a>sda');
#[('a', '/a/b', 'find more')]

總結

反向匹配在業務代碼中能用的地方不是很多,假如是純粹去掉html標簽的話,php有strip_tags,python也有對應的stripogram包,簡略用法看這里
多學一點,在leetcodecodewars這類的刷題網站里以最少的代碼量達到要求也能有成就感。
在這里掛個我的codewars肩章,歡迎一起來玩兒。

Reference

Does it repeat? - CodeGolf
揭開正則表達式的神秘面紗 - regexlab

備注:本文發布於2017-06-14,我github page的原文地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM