• 正则之反向引用


    前言

    某日在逛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'(.+)11','d123123123e');
    #['123']
     
    fa(r'(.+)11','d112233e');
    #[]
     
    #
    fa(r'((.+))12','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的原文地址

  • 相关阅读:
    python记录程序运行时间的三种方法
    LeetCode 922. 按奇偶排序数组 II 做题小结
    LeetCode 976. 三角形的最大周长 做题小结
    LeetCode 1122. 数组的相对排序 做题小结
    LeetCode1528. 重新排列字符串 做题小结
    LeetCode 738. 单调递增的数字 做题小结
    selenium——鼠标操作ActionChains:点击、滑动、拖动
    剑指 Offer 32
    剑指 Offer 32
    二叉树的应用:二叉排序树的删除
  • 原文地址:https://www.cnblogs.com/waltersgarden/p/7988780.html
Copyright © 2020-2023  润新知