在Python中对完全匹配的子字符串进行带约束的正则表达式匹配

3

由于这是一个正则表达式问题,这可能是一个重复的问题。

考虑这些给定的字符串

test_str = [
    "bla bla google.com bla bla", #0
    "bla bla www.google.com bla bla", #1
    "bla bla api.google.com bla bla", #2
    "google.com", #3
    "www.google.com", #4
    "api.google.com", #5
    "http://google.com", #6
    "http://www.google.com", #7
    "http://api.google.com", #8
    "bla bla http://www.google.com bla bla", #9
    "bla bla https://www.api.google.com bla bla" #10
]

我希望返回的结果是google.*或者www.google.*,但不包括api.google.*。也就是说,在上面的例子中,2、5、8、10都不应该匹配。
我尝试了几个正则表达式,但无法找到一行代码来完成这个任务。以下是我尝试过的内容。
re.compile("((http[s]?://)?www\.google[a-z.]*)") # match 1,4,7,9
re.compile("((http[s]?://)?google[a-z.]*)") # match all
re.compile("((http[s]?://)?.+\.google[a-z.]*)") # match except 0,3,6
re.compile("((http[s]?://)?!.+\.google[a-z.]*)") # match nothing

在这里,我正在寻找一种忽略 *.google.* 但保留 www.google.*google.* 的方法。但是,在寻找获取 *.google.* 的方法时遇到了困难。
PS:我已经找到了一个使用 split() 解决这个问题的 O(n**2) 方法。
r = re.compile("^((http[s]?://)?www.google[a-z.]*)|^((http[s]?://)?google[a-z.]*)")

for s in test_str:
    for seg in s.split():
        r.findall(seg)

请查看 https://ideone.com/3Cwfiu - Wiktor Stribiżew
谢谢。我有另一个问题要问你。如果api不是固定的,但我想筛选所有包括map.google.*calendar.google.*在内的API。这是否意味着我需要逐一添加它们? - Kir Chou
你可以使用回顾后发现的方法,这意味着你将不得不像(?<!\bapi)(?<!\bmap)这样链接回顾后发现,或者你可以使用基于前瞻的方法,例如r"(?<!\S)(?!\S*\b(?:map|api))\S*\bgoogle\b\S*",在其中你可以将黑名单术语添加到替代组中。 - Wiktor Stribiżew
谢谢您的解释。由于这是一种黑名单方式,我仍然对白名单方式很感兴趣。 - Kir Chou
对于白名单方法,我怀疑您提供的数据不足。规则是什么?只有在google之前的https?www(可选)?并且只在空格之间?请参见此演示 - Wiktor Stribiżew
1
@WiktorStribiżew 谢谢!我相信这就是我想要的。你的假设是正确的,http(s)和www在这里都是可选项。我需要学习更多关于回顾后断言的知识。请将您的答案放在下面,我会给您答复。 - Kir Chou
2个回答

1
您可以使用。
(?<!\S)(?:https?://)?(?:www\.)?google\.\S*

查看正则表达式演示

细节

  • (?<!\S) - 位于空格或字符串开头之前的位置(请注意,您也可以在此处使用(?:^|\s),以更明确)
  • (?:https?://)? - 匹配可选的 https://http:// 序列的可选非捕获组
  • (?:www\.)? 匹配可选的 www.序列的可选非捕获组
  • google\. - 匹配 google. 子字符串
  • \S* - 0个或多个非空格字符。

Python 演示

import re
test_str = [
    "bla bla google.com bla bla", #0
    "bla bla www.google.com bla bla", #1
    "bla bla api.google.com bla bla", #2
    "google.com", #3
    "www.google.com", #4
    "api.google.com", #5
    "http://google.com", #6
    "http://www.google.com", #7
    "http://api.google.com", #8
    "bla bla http://www.google.com bla bla", #9
    "bla bla https://www.api.google.com bla bla", #10
    "bla bla https://www.map.google.com bla bla" #11
]
r = re.compile(r"(?<!\S)(?:https?://)?(?:www\.)?google\.\S*")
for i,s in enumerate(test_str):
    m = r.search(s)
    if m:
        print("{}\t#{}".format(m.group(0), i))

输出:

google.com  #0
www.google.com  #1
google.com  #3
www.google.com  #4
http://google.com   #6
http://www.google.com   #7
http://www.google.com   #9

1
如果我的键盘正常工作,我将在半小时前回答。无论如何,我建议不要夸大正则表达式的复杂性。您可以使用宿主语言来管理黑名单(甚至是白名单),并使用re模块辅助。以下是我打包在一个脚本中的所有内容。显然,如果您需要将此代码集成到类或函数中,则可能需要进行一些重构:
import re

def main():
    input_urls = [ 
        "bla bla google.com bla bla",
        "bla bla www.google.com bla bla",
        # ...
    ]   
    filtered_urls = set()

    google_re = re.compile("(\w+\.)?google.com")
    blacklist = set(["api."])   # I didn't research enough to remove the dot

    for url in input_urls:
        # Beware of the difference between match() and search()
        # See https://docs.python.org/3/library/re.html#search-vs-match
        match = google_re.search(url)

        # The second condition will not be evaluated if the first fails
        if match is not None and match.group(1) not in blacklist:
            filtered_urls.add(url)

    print("Accepted URLs:", *filtered_urls, sep="\n\t", end="\n\n")
    print("Blacklisted URLs:", *(set(input_urls).difference(filtered_urls)), sep="\n\t")


if __name__ == "__main__":
    main()

很不幸,由于我的键盘上的 a 和 h 键无法使用,我无法快速找到删除 URL 位置中的点(例如 api.google、www.google、calendar.google 等)的方法。我强烈建议这样做。
在我的控制台上显示的输出为:
None@vacuum:~$ python3.6 ./filter.py 
Accepted URLs:
    http://google.com
    bla bla google.com bla bla
    bla bla www.google.com bla bla
    http://www.google.com
    google.com
    www.google.com
    bla bla http://www.google.com bla bla

Blacklisted URLs:
    api.google.com
    bla bla api.google.com bla bla
    http://api.google.com
    bla bla https://www.api.google.com bla bla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接