Нахождение неизвестного паттерна в строковом питоне

1

Я хорошо осведомлен о следующем вопросе, который также существует при переполнении стека. Строка Неизвестный шаблон. Соответствие, но ответ там не работает для меня.

Моя проблема следующая. Я получаю строку символов, например

  1. "1211", и мне нужно сделать, чтобы увидеть, что 1 чаще всего повторяется, и это 2 раза подряд.
  2. Но это также может быть "121212112", где 12 повторяется 3 раза подряд.
  3. Но с 12221221 221 повторяется 2 раза, а не 2, что повторяется 3 раза.

вот некоторые результаты, которые мне нравятся (единственные числа, которые когда-либо использовались, - 1 и 2)

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

результат я хочу, сколько раз это происходит.

Я понятия не имею, как начать поиск шаблона, поскольку он не известен на forehand, и я провел некоторое исследование в Интернете и не нашел ничего подобного.

Кто-нибудь знает, как я даже начинаю решать эту проблему? Вся помощь приветствуется, и если вы хотите получить дополнительную информацию, не стесняйтесь, дайте мне знать.

  • 1
    Можете ли вы описать точное поведение, которое вы хотите? Например, почему «12121212» следует рассматривать как «1212» два раза подряд, а не как «12» четыре раза или «12121212» один раз?
  • 1
    cs.stackexchange.com/a/79187/62807 может вам помочь?
Показать ещё 7 комментариев
Теги:
python-3.x

2 ответа

2

Действительно неэффективен, но вы можете

  1. найти все подстроки (qaru.site/questions/380826/...)
  2. поместите их в набор, чтобы избежать дублирования
  3. для каждой из подстрок, найти все его вхождения - и использовать некоторую функцию для поиска max (я не уверен, как вы выбираете между короткими строками, встречающимися много раз и длинными строками, встречающимися несколько раз)

Очевидно, вы можете использовать некоторую datastructure для прохождения через строку один раз и делать некоторые подсчеты на пути, но поскольку я не уверен, что ваши ограничения и желаемый результат, я могу дать вам только это.

  • 0
    что мне нужно, если я использую первую рекомендованную вами функцию (спасибо за это), так это то, что мне нужны дубликаты. потому что мне нужно получить самое длинное, что повторяется. Идея цикла for всплывает в памяти, но я не уверен, что это огромный обходной путь или нет.
  • 0
    @LibertyVerleysen Да, вам нужны дубликаты, но не на шаге 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

Если вас интересуют только две длины символов, вы можете легко вывести их из результатов 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
  • 0
    Я думаю, что я не могу выразить себя. Мне нужны только шаблоны, которые следуют друг за другом. поскольку за ним никогда не следует другой, это никогда не может быть паттерном. Что касается функции, то все, что я получил, это следующее назначение: «Напишите функцию, которая принимает строку. Функция должна возвращать длину самого длинного удвоенного суффикса этой строки».
  • 0
    Значит, это должны быть последовательные случаи?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню