正则表达式的使用,143题字符串‘chhc’字串权值求和问题 | 豆包MarsCode AI刷题

96 阅读2分钟

问题描述

小M正在研究一个由字母'c''h'组成的字符串,他的任务是计算该字符串所有子串中,出现的子串"chhc"的总次数。我们定义一个字符串的权值为其包含"chhc"子串的数量。你的任务是帮助小M求出整个字符串中所有子串的权值之和。

解决思路

在不考虑复杂度的情况下,我们只需要计算每一个字串中出现"chhc"的次数就可以了。首先需要生成所有的子串,然后对子串匹配"chhc",统计数目,然后相加即可,而对于字符串匹配,python中有str型自带的find(),可以返回匹配到的字符的下标,可以帮助我们快速找到是否有匹配。而这次我将使用re库和正则表达式来匹配字符串。

首先引入re库

import re

然后是生成子串与计算

def solution(s: str) -> int:
    # write code here
    s_len = len(s)
    count = 0
    for i in range(s_len):
        for size in range(1, s_len-i+1):
            count += len(re.findall(r'(?=(chhc))', s[i:i+size]))
    return count

这道题就完成了,总共也没有几行需要写的。

子串的生成由二层循环和数组切片来实现,这对python来说算是非常好操作的了,也是比较通用的全字串生成了。

for i in range(s_len):
    for size in range(1, s_len-i+1):
        s[i:i+size]

而我们这次所用上的re.findall()可以找到所有与模板匹配的所有串。而这需要用到正则表达式。

对于本题来说这次所使用到的正则表达式是'(?=(chhc))',这是一个正向前瞻断言的匹配,他会匹配所有chhc字符串但是不消耗字符。所以对chhchhc会正确匹配到2个,而不是1个,如果不使用(?=(chhc))而是chhc匹配,会导致消耗而无法按要求匹配。

正则表达式的使用

正则表达式用于广泛的字符匹配问题。以下先说一些基本的使用:

  • .:匹配任意一个字符(除了换行符 \n)。
  • ^:匹配字符串的开头。
  • $:匹配字符串的结尾。
  • *:匹配前面的子表达式零次或多次。
  • +:匹配前面的子表达式一次或多次。
  • ?:匹配前面的子表达式零次或一次。
  • []:定义一个字符类,匹配其中的任意一个字符。例如 [a-z] 匹配小写字母。
  • |:表示“或”运算符,用于匹配两个选择之一。例如 a|b 匹配字母 "a" 或字母 "b"。
  • ():分组,用来组合多个表达式,通常配合 | 或量词使用。
  • \d:匹配一个数字字符,等价于 [0-9]
  • \D:匹配一个非数字字符,等价于 [^0-9]
  • \w:匹配一个字母、数字或下划线字符,等价于 [a-zA-Z0-9_]
  • \W:匹配一个非字母、非数字、非下划线字符。
  • \s:匹配任何空白字符,包括空格、制表符、换行符等。
  • \S:匹配任何非空白字符。
  • {n}:匹配前面的子表达式恰好出现 n 次。
  • {n,}:匹配前面的子表达式至少出现 n 次。
  • {n,m}:匹配前面的子表达式出现 n 到 m 次

然后,我们可以看看在AI刷题中的其他的题目,例如第73题,SQL代码补全问题。

问题描述:

在开发SQL编辑器时,实现自动补全功能是提高用户体验的重要一环。小C需要实现一个功能,根据用户输入的字符片段,快速从已知的SQL关键字和数据库相关名称中找到所有以该片段开头的候选词,并按字典序输出。

例如,当用户输入 s 时,编辑器需要自动提示以 s 开头的所有可能选项,如 select。如果用户输入 fr,则需要提示 from 和 from_mobile。如果在提示中只有一个选项符合,如输入 from_ 时只提示 from_mobile

我用上的正则表达式匹配就是re.match(f'{input}\\w*',i):,这里的意思就是用变量input的内容替换后,以其开头的的任意长的仅有字母,数字和下划线组成的字符串,在变量i中的内容匹配。

附上源码:

def solution(num, data, input):
    # Please write your code here
    result=[]
    for i in data:
        if re.match(f'{input}\\w*',i):
            result.append(i)
    result.sort()
    temp=''
    for i,e in enumerate(result):
        if e==temp:
            result.pop(i)
        else:
            temp=e
    print(','.join(result))
    if result:
        return ','.join(result)
    else:
        return '-1'

或者第7题,创意标题匹配问题也可以用正则表达式来做

问题描述:

在广告平台中,为了给广告主一定的自由性和效率,允许广告主在创造标题的时候以通配符的方式进行创意提交。线上服务的时候,会根据用户的搜索词触发的 bidword 对创意中的通配符(通配符是用成对 {} 括起来的字符串,可以包含 0 个或者多个字符)进行替换,用来提升广告投放体验。例如:“{末日血战} 上线送 SSR 英雄,三天集齐无敌阵容!”,会被替换成“帝国时代游戏下载上线送 SSR 英雄,三天集齐无敌阵容!”。给定一个含有通配符的创意和n个标题,判断这句标题是否从该创意替换生成的。

我们只需要将{***}的内容替换成.*其他不变就可以,然后以其为模板去进行匹配就可以了。

源码如下:

import re

def solution(n, template_, titles):
    # Please write your code here
    result = []
    # 模板串生成
    template_ = template_.split('{')
    for i, e in enumerate(template_):
        if '}' in e:
            for index, c in enumerate(e):
                if c == '}':
                    temp = '.*' + e[index + 1:]
                    # temp = e[index + 1:]
                    break
            template_[i] = temp
    template=''.join(template_)
    for title in titles:
        if re.search(template,title):
            if len(re.search(template,title).group()) != len(title):
                result.append(False)
            else:
                result.append(True)
        else:
            result.append(False)
    result = ','.join(str(b) for b in result)
    return result
    

总结

对于这种需要字符串的匹配问题,我们可以使用正则表达式来匹配。可以使用较少的字符量就匹配到相应的内容。比如如果需要邮箱可以用"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"匹配,电话^\+?\d{1,3}-?\d{1,4}-?\d{4,10}$等因需要自行使用。也因此可以用于校验邮箱,号码,提取日志中的时间戳、IP 地址、URL 等信息。使用的场景十分的多样,我们也可以用于网络爬虫。在进行网页抓取时,正则表达式可以用于从 HTML 中提取出你需要的部分,如链接、图片、标题等。

总之,如果就是需要大量的文本处理和字符匹配问题就可以使用正则表达式,这可以让我们以较小的模板就匹配到我们所需要的内容。