【问题标题】:Python string pattern recognition/compressionPython字符串模式识别/压缩
【发布时间】:2010-12-27 05:16:51
【问题描述】:

我可以做基本的正则表达式,但这有点不同,即我不知道模式会是什么。

例如,我有一个类似字符串的列表:

lst = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']

在这种情况下,通用模式是两段通用文本:'sometxt''moretxt',以长度可变的其他内容开头和分隔。

普通字符串和可变字符串当然可以以任意顺序、任意次数出现。

将字符串列表压缩/压缩成它们的共同部分和个别变体的好方法是什么?

一个示例输出可能是:

c = ['sometxt', 'moretxt']

v = [('a','0'), ('b','1'), ('aa','10'), ('zz','999')]

【问题讨论】:

  • 这听起来很难。如果您提供更多背景知识可能会有所帮助,例如告诉您为什么必须完全使用这种压缩方案。
  • 等等,你不知道sometxtmoretxt 是什么以及它们在哪里?那将是一个相当大的技巧
  • 是的!给我们测试用例!
  • 很抱歉,如果我没有在问题中说清楚,不,我不知道“sometxt”和/或“moretxt”会是什么。输入是一系列用户定义的文本和机器生成的字符序列。我必须弄清楚每个输入项中的静态字符串和动态序列是什么。
  • 如何寻找外部工具,例如 Frak:github.com/noprompt/frak

标签: python string compression pattern-recognition


【解决方案1】:

这看起来很像用于数据(文本)压缩的LZW 算法。那里应该有 python 实现,您可以根据需要进行调整。

我假设您对这些经常重复的子字符串没有先验知识。

【讨论】:

    【解决方案2】:

    此解决方案找到两个最长的公共子字符串并使用它们来分隔输入字符串:

    def an_answer_to_stackoverflow_question_1914394(lst):
        """
        >>> lst = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']
        >>> an_answer_to_stackoverflow_question_1914394(lst)
        (['sometxt', 'moretxt'], [('a', '0'), ('b', '1'), ('aa', '10'), ('zz', '999')])
        """
        delimiters = find_delimiters(lst)
        return delimiters, list(split_strings(lst, delimiters))
    

    find_delimiters 和朋友找到分隔符:

    import itertools
    
    def find_delimiters(lst):
        """
        >>> lst = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']
        >>> find_delimiters(lst)
        ['sometxt', 'moretxt']
        """
        candidates = list(itertools.islice(find_longest_common_substrings(lst), 3))
        if len(candidates) == 3 and len(candidates[1]) == len(candidates[2]):
            raise ValueError("Unable to find useful delimiters")
        if candidates[1] in candidates[0]:
            raise ValueError("Unable to find useful delimiters")
        return candidates[0:2]
    
    def find_longest_common_substrings(lst):
        """
        >>> lst = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']
        >>> list(itertools.islice(find_longest_common_substrings(lst), 3))
        ['sometxt', 'moretxt', 'sometx']
        """
        for i in xrange(min_length(lst), 0, -1):
            for substring in common_substrings(lst, i):
                yield substring
    
    
    def min_length(lst):
        return min(len(item) for item in lst)
    
    def common_substrings(lst, length):
        """
        >>> list(common_substrings(["hello", "world"], 2))
        []
        >>> list(common_substrings(["aabbcc", "dbbrra"], 2))
        ['bb']
        """
        assert length <= min_length(lst)
        returned = set()
        for i, item in enumerate(lst):
            for substring in all_substrings(item, length):
                in_all_others = True
                for j, other_item in enumerate(lst):
                    if j == i:
                        continue
                    if substring not in other_item:
                        in_all_others = False
                if in_all_others:
                    if substring not in returned:
                        returned.add(substring)
                        yield substring
    
    def all_substrings(item, length):
        """
        >>> list(all_substrings("hello", 2))
        ['he', 'el', 'll', 'lo']
        """
        for i in range(len(item) - length + 1):
            yield item[i:i+length]
    

    split_strings 使用分隔符分割字符串:

    import re
    
    def split_strings(lst, delimiters):
        """
        >>> lst = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']
        >>> list(split_strings(lst, find_delimiters(lst)))
        [('a', '0'), ('b', '1'), ('aa', '10'), ('zz', '999')]
        """
        for item in lst:
            parts = re.split("|".join(delimiters), item)
            yield tuple(part for part in parts if part != '')
    

    【讨论】:

    • 投票反对(和一点)随机驾车。您的回答中有一些有趣且有用的东西。
    • 我们可能使用了不同版本的 python,我使用的是 2.4.3。我得到了 TypeError: min() 没有关键字参数。
    • 是的,我使用的是 2.5。我编辑了答案以使其适用于 2.4
    【解决方案3】:

    这似乎是longest common subsequence problem 的一个例子。一种方法是查看diffs 是如何生成的。 Hunt-McIlroy algorithm 似乎是第一个,并且是最简单的,尤其是因为它显然是非启发式的。

    第一个链接包含详细的讨论和(伪)代码示例。当然,假设我不完全了解这里的轨道。

    【讨论】:

    • 是的,我想到了差异算法。同样,只是不知道从哪里开始。
    【解决方案4】:

    这是一个可怕的让球滚动。

    >>> import re
    >>> makere = lambda n: ''.join(['(.*?)(.+)(.*?)(.+)(.*?)'] + ['(.*)(\\2)(.*)(\\4)(.*)'] * (n - 1))
    >>> inp = ['asometxt0moretxt', 'bsometxt1moretxt', 'aasometxt10moretxt', 'zzsometxt999moretxt']
    >>> re.match(makere(len(inp)), ''.join(inp)).groups()
    ('a', 'sometxt', '0', 'moretxt', '', 'b', 'sometxt', '1', 'moretxt', 'aa', '', 'sometxt', '10', 'moretxt', 'zz', '', 'sometxt', '999', 'moretxt', '')
    

    我希望它的丑陋会激发更好的解决方案:)

    【讨论】:

    • 漂亮的解决方案,有点慢,但我可以等待。丑陋并不困扰我,好的代码比黄金更有价值。从来没有想过以这种方式使用正则表达式,但这超出了我的基本正则表达式知识。我试图弄清楚如何将输出分成单独的常量和变量列表。
    • @iCy,如果输入数据中存在从未遇到过的字符,例如'\0',它的工作速度会显着加快。在这种情况下,将 ''.join 都替换为 '\0'.join。它还给出了更漂亮的结果。
    • 太棒了!是的,字符串只包含可打印的字符。 '\0'.join 让它更快。
    • 是的,这大大加快了速度。不过,我的解决方案仍然快 200 倍 :-) 拥有更多测试用例会很好...
    【解决方案5】:

    我想你应该从识别字符串中经常出现的子字符串(模式)开始。由于天真地计算一组字符串中的子字符串在计算上相当昂贵,因此您需要想出一些聪明的方法。

    我已经使用 generalized suffix trees (example here) 对大量数据进行了子字符串计数。一旦您知道数据中最常见的子字符串/模式,您就可以从那里获取它。

    【讨论】:

      【解决方案6】:

      将已知文本替换掉,然后拆分如何?

      import re
      [re.sub('(sometxt|moretxt)', ',', x).split(',') for x in lst]
      # results in
      [['a', '0', ''], ['b', '1', ''], ['aa', '10', ''], ['zz', '999', '']]
      

      【讨论】:

      • OP 不知道 sometxtmoretxt 是什么
      • @SilentGhost 老实说,我不确定他是否这样做。这个问题很不清楚。
      • @mavnn:让我们再读一遍:即我不知道模式会是什么。
      • @SilentGhost:鉴于它遵循我可以做基本的正则表达式...它可以被解读为我不知道如何构建所需的正则表达式模式 而不是 我不知道 sometxt 和 moretxt 的模式。不过,在后一种情况下,这是一个更有趣的问题。
      • 这就是 re.split 的用途。
      猜你喜欢
      • 1970-01-01
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 2015-04-03
      • 2023-02-01
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      相关资源
      最近更新 更多