如何排除包含常量字符串的正则表达式匹配

时间:2019-12-01 11:20:02

标签: python regex expression

我需要帮助来了解正则表达式中的排除项。

我从Jupyter笔记本开始:

import re

file = open('names.txt', encoding='utf-8')
data = file.read()
file.close()

然后我无法执行排除规则。读取的文件中包含12个电子邮件字符串,其中3个包含“ .gov”。

有人告诉我,这只会返回不是.gov的那些文件:

re.findall(r'''
    [-+.\w\d]*\b@[-+\w\d]*.[^gov]
''', data, re.X|re.I)

不是。它返回所有电子邮件,并在“ @”之后的“ gov”中排除任何字符;例如:

abc123@abc.c     # 'o' is in 'gov' so it ends the returned string there
456@email.edu
governmentemail@governmentaddress.      #'.gov' omitted

我尝试使用?!我在网上发现各种各样的形式都无济于事。

例如,有人告诉我以下语法将排除整个匹配项,而不仅仅是那些字符:

#re.findall(r'''
#    ^/(?!**SPECIFIC STRING TO IGNORE**)(**DEFINITION OF STRING TO RETURN**)$
#''', data, re.X|re.I)

但是以下内容仅返回一个空列表:

#re.findall(r'''
#    ^/(?!\b[-+.\w\d]*@[-+.\w\d]*.gov)([-+.\w\d]*@[-+.\w\d].[\w]*[^\t\n])$
#''', data, re.X|re.I)

我尝试使用此问题的建议:

Regular expression to match a line that doesn't contain a word

re.findall(r'''

    [-+.\w\d]*\b@[-+\w\d]*./^((?!.gov).)*$/s  # based on syntax /^((?!**SUBSTRING**).)*$/s
                          #^ this slash is where different code starts
''', data, re.X|re.I)

这应该是内联语法,我认为通过包含斜杠,我可能会犯一个错误:

re.findall(r'''
    [-+.\w\d]*\b@[-+\w\d]*./(?s)^((?!.gov).)*$/  # based on syntax /(?s)^((?!**SUBTRING**).)*$/
''', data, re.X|re.I)

这将返回一个空列表:

re.findall(r'''
    [-+.\w\d]*\b@[-+\w\d]*.(?s)^((?!.gov).)*$  # based on syntax (?s)^((?!**SUBTRING**).)*$
''', data, re.X|re.I)

请帮助我了解如何使用?!或^或其他排除语法,以返回不包含另一个指定字符串的指定字符串。

谢谢!

2 个答案:

答案 0 :(得分:1)

关于您尝试过的模式的一些注释

  • 模式[-+.\w\d]*\b@的这一部分可以缩短为[-+.\w]*\b@,因为\w也与\d匹配,请注意,它也将不与点匹配。

  • 使用[-+.\w\d]*\b@可以防止破折号在@之前匹配,但可以匹配---a@.a

  • 字符类[-+.\w\d]*被重复0+次,但是它永远不能匹配0+次,因为单词边界\b在空白或行首与{{ 1}}

  • 请注意,不转义点@会匹配除换行符以外的任何字符

  • 这部分.是一个tempered greedy token,它将从字符串的开头匹配任何字符,除了换行符,断言右边的字符除换行符后跟{{ 1}},直到字符串结尾

一种选择可能是使用经过调节的贪婪令牌来断言^((?!.gov).)*$之后不存在gov

@

有关各个部分的说明

  • .gov匹配1次以上列出的任何游戏
  • [-+.\w]+\b@(?:(?!\.gov)\S)+(?!\S) 单词边界和匹配[-+.\w]+
  • \b@非捕获组
    • @负向前进,断言右边的不是
      • (?:匹配(?!
    • \.gov提前关闭
    • .gov匹配非空格字符
  • )关闭非捕获组并重复1次以上
  • \S负向查找,断言右边的内容是非空格字符,以防止部分匹配

Regex demo


您可以通过不匹配)+或空白字符,然后匹配(?!\S)然后再匹配不存在字符串@的非空白字符来使模式更宽: / p>

@

Regex demo

答案 1 :(得分:1)

首先,您用于识别电子邮件地址的正则表达式看起来不太正确。例如,它将接受@13a为有效。有关一些简化,请参见How to check for valid email address?。我将使用:[^@]+@[^@]+\.[^@]+,同时建议您也排除空格字符,因此,在您的特定情况下:

^([^@\s]+@[^@\s]+\.[^@\s.]+)

我还向最后一个字符类.添加了[^@\s.]+,以确保它表示顶级域。但是我们不希望电子邮件地址以.gov结尾。我们的正则表达式会在最后指定匹配顶级域名的地方:

  1. \.匹配句号。
  2. [^@\s.]+匹配一个或多个非空格,非句点字符。

在上面的步骤2中,我们应该首先应用负向超前,即确保下一个字符不是gov的条件。但是要确保我们不进行部分匹配(如果顶级域为government,那可以),gov后必须跟空格或行尾取消资格。所以我们有:

^([^@\s]+@[^@\s]+\.(?!gov(?:\s|$))[^@\s.]+)

See Regex Demo

import re

text = """abc123@abc.c     # 'o' is in 'gov' so it ends the returned string there
456@email.edu
governmentemail@governmentaddress.      #'.gov' omitted
test@test.gov
test.test@test.org.gov.test
"""

print(re.findall(r'^([^@\s]+@[^@\s]+\.(?!gov(?:\s|$))[^@\s.]+)', text, flags=re.M|re.I))

打印:

['abc123@abc.c', '456@email.edu', 'test.test@test.org.gov.test']

因此,在我对问题test.test@test.org.gov.test的理解中,因为gov not 的顶级域。 governmentemail@governmentaddress.被拒绝是因为它不是有效的电子邮件地址。

如果您不希望在域的任何级别使用gov,请使用此正则表达式:

^([^@\s]+@(?!(?:\S*\.)?gov(?:\s|\.|$))[^@\s]+\.[^@\s]+)

See Regex Demo

在看到@符号之后,这可以确保后面的内容不是一个可选的句点,后面跟着gov,后面是另一个句点,空格字符或行尾。

import re

text = """abc123@abc.c     # 'o' is in 'gov' so it ends the returned string there
456@email.edu
governmentemail@governmentaddress.      #'.gov' omitted
test@test.gov
test.test@test.org.gov.test
"""

print(re.findall(r'^([^@\s]+@(?!(?:\S*\.)?gov(?:\s|\.|$))[^@\s]+\.[^@\s]+)', text, flags=re.M|re.I))

打印:

['abc123@abc.c', '456@email.edu']