繁体   English   中英

RegExp:删除字符串中可以包含其他句点的最后一个句点(挖掘输出)

[英]RegExp: Remove last period in string that can contain other periods (dig output)

我试图解析linux dig命令的输出,并使用正则表达式一次完成几项操作。

假设我挖了主机mail.yahoo.com

/usr/bin/dig +nocomments +noquestion \
    +noauthority +noadditional +nostats +nocmd \
    mail.yahoo.com A

该命令输出:

mail.yahoo.com.                   0  IN  CNAME  login.yahoo.com.
login.yahoo.com.                  0  IN  CNAME  ats.login.lgg1.b.yahoo.com.
ats.login.lgg1.b.yahoo.com.       0  IN  CNAME  ats.member.g02.yahoodns.net.
ats.member.g02.yahoodns.net.      0  IN  CNAME  any-ats.member.a02.yahoodns.net.
any-ats.member.a02.yahoodns.net. 12  IN  A      98.139.21.169

我想要找到的所有<host><record_type><resolved_name>部分都没有最后一个句号,而只使用一个正则表达式

对于带有mail.yahoo.com特定示例,它将为:

[
    ('mail.yahoo.com', 'CNAME', 'login.yahoo.com'),
    ('login.yahoo.com', 'CNAME', 'ats.login.lgg1.b.yahoo.com'),
    ('ats.login.lgg1.b.yahoo.com', 'CNAME', 'ats.member.g02.yahoodns.net'),
    ('ats.member.g02.yahoodns.net', 'CNAME', 'any-ats.member.a02.yahoodns.net'),
    ('any-ats.member.a02.yahoodns.net', 'A', '98.139.21.169'),
]

但是事实证明, dig命令可能会在名称末尾显示一个句点:

    mail.yahoo.com. 
        ^     ^   ^
        |     |   |
  Good dot    |   |
              |   |
        Good dot  |
                  |
           (!) Baaaad dot

进行正则表达式拆分dig的输出并返回带有最后一个句点的名称非常简单:

regex = re.compile("^(\S+).+IN\s+([A-Z]+)\s+(\S+)\.*\s*$",re.MULTILINE)

但是使用该正则表达式调用.findall确实会返回主机中的最后一个句点,因为\\S+也将匹配最后一个句点:

[
    ('mail.yahoo.com.', 'CNAME', 'login.yahoo.com.'),
    ('login.yahoo.com.', 'CNAME', 'ats.login.lgg1.b.yahoo.com.'),
    ('ats.login.lgg1.b.yahoo.com.', 'CNAME', 'ats.member.g02.yahoodns.net.'),
    ('ats.member.g02.yahoodns.net.', 'CNAME', 'any-ats.member.a02.yahoodns.net.'),
    ('any-ats.member.a02.yahoodns.net.', 'A', '98.139.21.169'),
]

所以,我需要匹配所有非空格的东西 \\S ,除非它是一个周期+空格。

我已经进行了无数次尝试,但还没有想出一个像样的解决方案。

先感谢您!

PS:我知道我总是可以使用“简单”的正则表达式并(在第二遍中)删除找到的字符串的最后一个点,但是我很好奇能否通过一次使用正则表达式来完成。

但是使用该正则表达式调用.findall确实会返回主机中的最后一个句点,因为\\S+也将匹配最后一个句点…

这里有两个问题。

首先,一旦用反斜杠转义,就需要使用原始字符串文字( r"…" ),否则也必须转义反斜杠。 我实际上不确定您的任何反斜杠前缀字符是否都与Python反斜杠转义序列匹配,但这本身就足以使用原始字符串文字,因此您的读者不必查找确切的字符串规则。

其次,此问题的一般情况是正则表达式重复默认情况下是贪婪的:它们将尽可能匹配,同时仍允许其余模式匹配; 当您希望它们尽可能地匹配而又允许其余模式匹配时,您需要添加一个? +*

在您的特殊情况下, \\S+可以匹配包括final在内的所有内容. ,并且\\.*\\s*将成功匹配0 . s和0个空格。 但是\\S+? 将离开决赛. 对于模式的下一部分。 您也可以通过在第一个组后面添加一个句号来将其强制出第一组。 像这样:

^(\S+)\..+IN\s+([A-Z]+)\s+(\S+?)\.*\s*$

正则表达式可视化

Debuggex演示

您可以简单地强制在组末尾没有句号(并且它不包含空格):

npg = '([^\.\s]+(?:.[^\.\s]+)*)' #not_period_ending_group
regex = re.compile("^" + npg + ".+IN\s+([A-Z]+)\s+" + npg +".+$",re.MULTILINE)

您可以将此模式与多行修饰符一起使用:

^([^ ]+)(?<!\.)\.?[ ]+[0-9]+[ ]+IN[ ]+([^ ]+)[ ]+(.+(?<!\.))\.?$

$ 1,$ 2和$ 3中存储的组

DEMO

编辑:试试这个:

^([^ \t]+)(?<!\.)\.?[ \t]+[0-9]+[ \t]+IN[ \t]+([^ \t]+)[ \t]+(.+(?<!\.))\.?$

作为替代答案,我建议使用str.split() ,如果您的字符串行位于类似L的列表中, str.split()

[(line[0][:-1],line[3],line[4][:-1]) for line in L]

注意[:-1]删除最后一个. 来自主机地址!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM