повторяющиеся буквы в Python - PullRequest
3 голосов
/ 06 августа 2011

Как лучше всего ограничить количество повторяющихся букв до 1 и 2, например:
appppppppple => апель и яблоко
bbbbbeeeeeer => ber, пиво, bber, bbeer

Прямо сейчас у меня есть это:

a = "hellllllllllooooooooooooo"
    match = re.search('(.)\\1+', a)

    if match:
        print 'found'
        print re.sub('(.)\\1+', '\\1', a)
        print re.sub('(.)\\1+', '\\1\\1', a)
    else:
        print 'not found'

Но возвращается только:

helo
helloo

Как я могу заставить его работать так, как я хочу?

Ответы [ 3 ]

5 голосов
/ 06 августа 2011

Не используйте RE для этого.RE хороши для поиска, сопоставления и преобразования, но не для генерации строк.

Мы можем рассматривать строку как вектор;каждая буква - это измерение, а количество повторений - это длина компонента вдоль этого измерения.Для данного вектора V вам нужны все возможные векторы того же измерения, что и V, так что значение каждого компонента равно 1, если соответствующий компонент V равен 1, или равно 1 или 2 в противном случае.Исходя из этого, вот функция, которая делает то, что вы хотите.

def doppelstring(s):
    letter_groups = ((val, list(group)) for val, group in itertools.groupby(s))
    max_vector = ((val, min(len(group), 2)) for val, group in letter_groups)
    vector_components = ([dim * (l + 1) for l in range(maxlen)] for dim, maxlen in max_vector)
    return [''.join(letters) for letters in itertools.product(*vector_components)]

Вот более компактная версия, которая использует нарезку.Он может быть немного менее читабельным, но, по крайней мере, не выходит за предел в 78 символов:

def doppelstring(s):
    max_vs = (''.join(itertools.islice(g, 2)) for k, g in itertools.groupby(s))
    components = ([s[:l + 1] for l in range(len(s))] for s in max_vs)
    return [''.join(letters) for letters in itertools.product(*components)]
2 голосов
/ 06 августа 2011
import re

def permute(seq):
    if len(seq) < 2:
        yield seq
    else:
        for tail in permute(seq[2:]):
            yield seq[:2] + tail
            yield seq[:2] + seq[1:2] + tail

text = "hellllllllllooooooooooooo"
seq = re.split('(.)\\1+', text)

for result in permute(seq):
    print ''.join(result)
0 голосов
/ 06 августа 2011

Вот первый без регулярных выражений способ, который всплыл в моей голове

Сначала создайте общую squeeze функцию:

def squeeze(str, chars='abcdefghijklmnopqrstuvwxyz', min=1): 
    new_str = str
    for c in chars:
        new_str = new_str.replace(c*(1+min),c*min)
    if new_str != str:
        new_str = squeeze(new_str, min=min)
    return new_str

>>> squeeze('aaaabbbbcccc')
'abc'
>>> squeeze('aaaabbbbcccc', min=2)
'aabbcc'

Тогда мы можем написать небольшую функцию, которая будет выдавать каждую 'сжимаемую перестановку' и может использоваться для инициализации set:

def squeezutations(str):
    str = squeeze(str, chars=set(str), min=2)
    for j,k in ((j,k) for j in range(2,0,-1) for k in range(1,3)):
        for c in set(str):
            yield squeeze(squeeze(str, chars=c, min=k), chars=set(str)-set(c), min=j )

>>> set(squeezutations('appppppppple'))
set(['apple', 'aple'])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...