【问题标题】:Grouping text lines so if A=B and B=C, then A=C将文本行分组,如果 A=B 且 B=C,则 A=C
【发布时间】:2014-10-23 19:38:40
【问题描述】:

我目前正在处理解析dig 命令的输出。该命令输出规范名称,然后输出最后一条记录的实际 IP。

例如,解析dig mail.yahoo.com 会执行以下操作:

borrajax@borrajax.kom /tmp/ $ dig @8.8.8.8 @4.2.2.2 +nocomments \
     +noquestion +noauthority +noadditional \
     +nostats +nocmd mail.yahoo.com

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. 49 IN  A   98.139.21.169

所以我希望能够说mail.yahoo.com 解析为98.139.21.169,为此,我需要将mail.yahoo.com“合并”到login.yahoo.com,然后将login.yahoo.com 合并到@987654330 @...等...直到到达最后一个A记录。

another question 中,我已经有了一个很好的正则表达式来解析dig 的输出,所以我可以很好地清理这些行并将其存储到一个列表中:

[
    ('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')
]

问题是:我怎样才能有效地以一般方式做到这一点,所以如果我在CNAMEs 之间有一些其他随机线,它也可以工作:

[
    ('mail.yahoo.com', 'CNAME', 'login.yahoo.com'),
    ('foo.com', 'CNAME', 'baz.com'),    # Wooops, watch out!
    ('login.yahoo.com', 'CNAME', 'ats.login.lgg1.b.yahoo.com'),
    ('ats.login.lgg1.b.yahoo.com', 'CNAME', 'ats.member.g02.yahoodns.net'),
    ('baz.com', 'A', '204.236.134.199'), # Wooops, watch out!
    ('ats.member.g02.yahoodns.net', 'CNAME', 'any-ats.member.a02.yahoodns.net'),
    ('any-ats.member.a02.yahoodns.net', 'A', '98.139.21.169')
]

所需的输出是:

  • mail.yahoo.com 解析为 98.139.21.169
  • foo.com 解析为 204.236.134.199

当然,我可以检查所有 CNAMES 以及每次找到它时实际解析的内容,但那将是 O(n^2)... 这太可怕了。

我确信有更好的方法,但我想不出任何方法。提前感谢您的任何想法。

【问题讨论】:

  • 第一个/原始查询的 ip 地址(你想要的那个)是否总是像这样显示为所有文本的最后一项??
  • 另外,在您遇到另一个不想要的地址的示例中,它最终是 ip,我注意到它有点嵌套在原始查询和解析中,总是这样吗?
  • 确实如此,但这个特殊的“问题”让我思考如何在更随机的场景中解决这个问题
  • 随机,因为有时不是这样?其他 ip 紧随其后?
  • 是的,就像...一个完全未分类的疯狂输出 :-)

标签: python sorting text merge


【解决方案1】:

我会建立一个dict 并从那里解决链:

data = [
    ('mail.yahoo.com', 'CNAME', 'login.yahoo.com'),
    ('foo.com', 'CNAME', 'baz.com'),    # Wooops, watch out!
    ('login.yahoo.com', 'CNAME', 'ats.login.lgg1.b.yahoo.com'),
    ('ats.login.lgg1.b.yahoo.com', 'CNAME', 'ats.member.g02.yahoodns.net'),
    ('baz.com', 'A', '204.236.134.199'), # Wooops, watch out!
    ('ats.member.g02.yahoodns.net', 'CNAME', 'any-ats.member.a02.yahoodns.net'),
    ('any-ats.member.a02.yahoodns.net', 'A', '98.139.21.169')
]

data = { t[0]:t[1:] for t in data }

def lookup(host):
    record_type = None
    while record_type != 'A':
        record_type, host = data[host]
    return host

assert lookup('mail.yahoo.com') == '98.139.21.169'
assert lookup('foo.com') == lookup('baz.com') == '204.236.134.199'

【讨论】:

    【解决方案2】:

    这是我的解决方案(有关算法的更多信息,请参阅 cmets):

    import copy
    
    def resolve(arr):
        # create an index for easy access of the urls
        index = {item[0]: item[2] for item in arr}
        # copy the index 
        mapping = copy.copy(index)
    
        # loop through the index
        for index_key in index: 
            # get the current value
            value = index[index_key]
            # loop through the mapping as long as the final ip address is reached
            # but only if this url wasn't found before
            while value in mapping:
                # remember the new key (so it can be deleted afterwards)
                key = value
                # get the new value
                value = mapping[key]
                # save the found value as the new value (for later use)
                # this reduces the complexity (-> better performance)
                mapping[index_key] = value
                # delete the "one in the middle" out of the mapping array
                # so that the next item don't have to search for 
                # the correct mapping (because the mapping has been found already)
                del mapping[key]
    
        return mapping
    

    使用此脚本,您可以看到无论列表如何排序,它都会生成相同的输出:

    import random
    
    data = [
        ('mail.yahoo.com', 'CNAME', 'login.yahoo.com'),
        ('foo.com', 'CNAME', 'baz.com'),    # Wooops, watch out!
        ('login.yahoo.com', 'CNAME', 'ats.login.lgg1.b.yahoo.com'),
        ('ats.login.lgg1.b.yahoo.com', 'CNAME', 'ats.member.g02.yahoodns.net'),
        ('baz.com', 'A', '204.236.134.199'), # Wooops, watch out!
        ('ats.member.g02.yahoodns.net', 'CNAME', 'any-ats.member.a02.yahoodns.net'),
        ('any-ats.member.a02.yahoodns.net', 'A', '98.139.21.169')
    ]
    
    # test 50 times
    for x in xrange(50):
        # shuffle the data array
        random.shuffle(data)
    
        print resolve(data)
    

    【讨论】:

    • 感谢您的想法。我想到了类似的东西(它实际上涉及listpop,这将等同于while/del 构造......这仍然可能是O(n^2),对吧?
    • 我觉得复杂度更像O(2n log(n)),因为我把已经找到的url保存在映射数组中。这降低了复杂性,但我不知道这是否可以用 log 或 O 表示法中的其他内容来描述......
    • 查看源代码中的 cmets 了解有关降低复杂性的更多详细信息
    猜你喜欢
    • 2015-05-01
    • 1970-01-01
    • 2012-09-03
    • 2011-08-01
    • 2015-06-12
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多