Проверка шаблона в строке Python - PullRequest
1 голос
/ 10 апреля 2019

Предположим, у нас есть строки типа:

test= '--a-kbb-:xx---xtx:-----x--:---g-x--:-----x--:------X-:XXn-tt-X:l--f--O-'

то есть они всегда состоят из 8 разделов, разделенных :, поэтому можно разбить строку на список, каждый элемент которого соответствует разделу:

testsep = test.split(':')

1008 * дает *

['--a-kbb-', 'xx---xtx', '-----x--', '---g-x--', '-----x--', '------X-', 'XXn-tt-X', 'l--f--O-']

Теперь я хочу проверить, является ли строка test такой, что в 3 последовательных секциях x встречается в той же позиции секции. Например, с приведенным выше test мы находим по крайней мере один такой случай: при подсчете 1 в разделах 2,3 и 4 содержится x в той же позиции, а именно в индексе 6. Поэтому наша тестовая строка здесь соответствует требуемому шаблону.

  • Существует ли простой (возможно, функциональный) способ проверки таких шаблонов, если строки всегда составляются с форматированием, приведенным выше?

Наивным подходом было бы разделение, затем цикл по всем разделам и проверка наличия последовательных разделов, имеющих x в каждой возможной позиции (первый индекс 1, 2, ... до 8), но это не будет очень похоже на питона.

Ответы [ 3 ]

2 голосов
/ 10 апреля 2019

Достаточно ли этого питона?

str = '--a-kbb-:xx---xtx:-----x--:---g-x--:-----x--:------X-:XXn-tt-X:l--f--O-'
sections = str.split (':')
reduce (lambda a, b: a | ('xxx' in b), [reduce(lambda c, d: c + d, map(lambda c: c[i], sections), '') for i in range(reduce (lambda e, f: max (e, len (f)), sections, 0))], False)

Объяснение

reduce (lambda e, f: max (e, len (f)), sections, 0)

рассчитывает максимальную длину сечения;

for i in range(reduce (lambda e, f: max (e, len (f)), sections, 0))

повторяет i от нуля до максимальной длины секции минус 1;

map(lambda c: c[i], sections)

вычисляет список i-тых символов всех разделов;

reduce(lambda c, d: c + d, map(lambda c: c[i], sections), '')

вычисляет строку, состоящую из i-тых символов всех секций;

[reduce(lambda c, d: c + d, map(lambda c: c[i], sections), '') for i in range(reduce (lambda e, f: max (e, len (f)), sections, 0))]

вычисляет список строк, где i-я строка состоит из i-го символа всех секций;

и окончательное выражение возвращает True в случае, если любая из строк в списке, вычисленных на предыдущем шаге, содержит три последовательных символа «x».

2 голосов
/ 10 апреля 2019

Выберите каждый 9-й элемент и проверьте, есть ли 3 последовательных символа x:

test= '--a-kbb-:xx---xtx:-----x--:---g-x--:-----x--:------X-:XXn-tt-X:l--f--O-'
for i in range(9):
    if 'xxx' in test[i::9]:
        print("Pattern matched at position %d" % i)
        break
else:
    print("Pattern not matched")

дает

Pattern matched at position 5

Короткая версия:

>>> any(('xxx' in test[i::9] for i in range(9)))
True
2 голосов
/ 10 апреля 2019

Можно использовать itertools.groupby с class для группировки серий строк, у которых все имеют x в одной позиции:

from itertools import groupby
class X:
  def __init__(self, _x):
    self.x = _x
  def __eq__(self, _val):
    return any(a == 'x' and b =='x' for a, b in zip(self.x, _val.x))

d = ['--a-kbb-', 'xx---xtx', '-----x--', '---g-x--', '-----x--', '------X-', 'XXn-tt-X', 'l--f--O-']
result = [[a, [i.x for i in b]] for a, b in groupby(list(map(X, d)))]
final_result = [b for _, b in result if any(all(h == 'x' for h in c) for c in zip(*b))] 

Выход:

[['xx---xtx', '-----x--', '---g-x--', '-----x--']]

Тем не менее, гораздо проще использовать наивный подход, и, действительно, решение довольно питонское:

def group(d):
  start = [d[0]]
  for i in d[1:]:
    if any(all('x' == c for c in b) for b in zip(*(start+[i]))):
       start.append(i)
    else:
       if len(start) > 1:
         yield start
       start = [i]

print(list(group(d)))

Вывод:

[['xx---xtx', '-----x--', '---g-x--', '-----x--']]
...