在字符串python中查找未知模式

时间:2018-09-01 13:12:41

标签: python python-3.x

我很清楚以下问题,该问题在堆栈溢出String Unknown pattern Matching上也存在,但是那里的答案对我来说真的不起作用。

下一个是我的问题。我得到一串字符,例如

  
      
  1. “ 1211”,我需要做的是看到最常重复1   并连续2次。
  2.   
  3. 但是它也可以是“ 121212112”,其中12重复3次   行。
  4.   
  5. 但是对于12221221,它是221,重复了2次而不是2次   重复3次。
  6.   

这是我想要得到的一些结果(曾经使用过的唯一数字是1和2)

>>> counter('1211')
1
>>> counter('1212')
2
>>> counter('21212')
2

我想要的结果是它发生了多少次。

我不知道该如何开始寻找一种模式,因为它不是正手就知道的,而且我在网上做了一些研究,没有发现任何类似的东西。

有人知道我怎么开始解决这个问题吗?欢迎所有帮助,如果您需要更多信息,请随时告诉我。

2 个答案:

答案 0 :(得分:2)

效率很低,但是您可以

  1. 找到所有子字符串(https://stackoverflow.com/a/22470047/264596
  2. 将它们放入集合中以避免重复
  3. 对于每个子字符串,找到所有出现的子字符串-并使用一些函数来找到最大值(我不确定如何在多次出现的短字符串和多次出现的长字符串之间进行选择)

很明显,您可以使用一些数据结构一次通过字符串并进行一些计数,但是由于我不确定您的约束和期望的输出是什么,因此我只能给您这个信息。

答案 1 :(得分:0)

我同意Jirka的看法,不确定要如何选择最佳成绩的长还是短得分,但是此功能将为您提供菜单:

#Func1
def sub_string_cts(string):
    combos = {}
    for i in range(len(string)):
        u_start = len(string) - i
        for start in range(u_start):
            c_str = string[start:i+start+1]

            if c_str in combos:
                combos[c_str] += 1
            else:
                combos[c_str] = 1
    return combos

sub_string_cts('21212')

{'2': 3,
 '1': 2,
 '21': 2,
 '12': 2,
 '212': 2,
 '121': 1,
 '2121': 1,
 '1212': 1,
 '21212': 1}

发表评论后,我认为这是您所寻找的更多内容:

#Func2
def sub_string_cts(string):
    combos = {}
    for i in range(len(string)):
        u_start = len(string) - i
        substrs = set([string[start:i+start+1] for start in range(u_start)])
        for substring in substrs:
            combos[substring]  = max([len(i) for i in re.findall("((?:{})+)".format(substring), string)])//len(substring)

    return combos

sub_string_cts('21212')

{'2': 1,
 '1': 1,
 '21': 2,
 '12': 2,
 '212': 1,
 '121': 1,
 '2121': 1,
 '1212': 1,
 '21212': 1}

您可以通过折叠每个字符串长度最高的出现实例,将其范围缩小到“最佳”候选:

def max_by_len(result_dict):
    results = {}
    for k, v in result_dict.items():
        if len(k) not in results:
            results[len(k)] = {}

    for c_len in [ln for ln in results]:
        len_max_count = max([v for (k, v) in result_dict.items() if len(k) == c_len])
        for k,v in result_dict.items():
            if len(k) == c_len:
                if v == len_max_count:
                    results[c_len][k] = v
    return results

#Func1:
max_by_len(sub_string_cts('21212'))

{1: {'2': 3},
 2: {'21': 2, '12': 2},
 3: {'212': 2},
 4: {'2121': 1, '1212': 1},
 5: {'21212': 1}}

#Func2:
max_by_len(sub_string_cts('21212'))

{1: {'2': 1, '1': 1},
 2: {'21': 2, '12': 2},
 3: {'212': 1, '121': 1},
 4: {'2121': 1, '1212': 1},
 5: {'21212': 1}}

假设我们不会选择“ 2121”或“ 1212”,因为它们的出现与“ 21212”相匹配且长度较短,并且类似地,我们也不会选择“ 21”或“ 12”,因为它们出现在与“ 212”的频率相同,我们可以使用以下代码将可行的候选对象限制为“ 2”,“ 212”和“ 21212”:

def remove_lesser_patterns(result_dict):
    len_lst = sorted([k for k in result_dict], reverse=True)
    #len_lst = sorted([k for k in max_len_results])
    len_crosswalk = {i_len: max([v for (k,v) in result_dict[i_len].items()]) for i_len in len_lst}

    for i_len in len_lst[:-1]:
        eval_lst = [i for i in len_lst if i < i_len]

        for i in eval_lst:
            if len_crosswalk[i] <= len_crosswalk[i_len]:
                if i in result_dict:
                    del result_dict[i]
    return result_dict

#Func1
remove_lesser_patterns(max_by_len(sub_string_cts('21212')))

{1: {'2': 3}, 3: {'212': 2}, 5: {'21212': 1}}

#Func2
remove_lesser_patterns(max_by_len(sub_string_cts('21212')))

{2: {'21': 2, '12': 2}, 5: {'21212': 1}}

结果:

test_string = ["1211", "1212", "21212", "12221221"]
for string in test_string:
    print("<Input: '{}'".format(string))
    c_answer = remove_lesser_patterns(max_by_len(sub_string_cts(string)))
    print("<Output: {}\n".format(c_answer))

<Input: '1211'
<Output: {1: {'1': 2}, 4: {'1211': 1}}
# '1' is repeated twice

<Input: '1212'
<Output: {2: {'12': 2}, 4: {'1212': 1}}
# '12' is repeated twice

<Input: '21212'
<Output: {2: {'21': 2, '12': 2}, 5: {'21212': 1}}
# '21' and '12' are both repeated twice

<Input: '12221221'
<Output: {1: {'2': 3}, 3: {'221': 2}, 8: {'12221221': 1}}
# '2' is repeated 3 times, '221' is repeated twice

这些函数一起为您提供每种图案出现次数最多的长度。字典的关键是长度,其子字典具有最高的出现模式(如果并列,则为多个)。

Func2要求模式是顺序的,而Func1则不需要-严格基于出现。


注意:

以您的示例为例:

3. But with 12221221 it is 221 that is repeated 2 times rather than 2 that repeats 3 times.

代码为您提供了以下两种解决方案,以解决您期望的输出(2或3)中的歧义:

<Input: '12221221'
<Output: {1: {'2': 3}, 3: {'221': 2}, 8: {'12221221': 1}}
# '2' is repeated 3 times, '221' is repeated twice

如果您只对2个字符长度感兴趣,则可以按照以下步骤轻松地将其从max_by_len结果中拉出:

test_string = ["1211", "1212", "21212", "12221221"]
for string in test_string:
    print("<Input: '{}'".format(string))
    c_answer = remove_lesser_patterns({k:v for (k,v) in max_by_len(sub_string_cts(string)).items() if k == 2})
    print("<Output: {}\n".format(max([v for (k,v) in c_answer[2].items()])))
#Func2
<Input: '1211'
<Output: 1

<Input: '1212'
<Output: 2

<Input: '21212'
<Output: 2

<Input: '12221221'
<Output: 1