Я пытаюсь поймать, если одна буква, которая появляется дважды в строке, используя RegEx (или, может быть, есть несколько лучших способов?), Например, моя строка:

ugknbfddgicrmopn

Результатом будет:

dd

Тем не менее, я пробовал что-то вроде:

re.findall('[a-z]{2}', 'ugknbfddgicrmopn')

Но в этом случае он возвращает:

['ug', 'kn', 'bf', 'dd', 'gi', 'cr', 'mo', 'pn']   # the except output is `['dd']`

У меня также есть способ получить ожидаемый результат:

>>> l = []
>>> tmp = None
>>> for i in 'ugknbfddgicrmopn':
...     if tmp != i:
...         tmp = i
...         continue
...     l.append(i*2)
...     
... 
>>> l
['dd']
>>> 

Но это слишком сложно ...


Если это 'abbbcppq', тогда только поймать:

abbbcppq
 ^^  ^^

Итак, результат:

['bb', 'pp']

Затем, если это 'abbbbcppq', поймайте bb дважды:

abbbbcppq
 ^^^^ ^^

Итак, результат:

['bb', 'bb', 'pp']
57
Casimir Crystal 14 Дек 2015 в 10:00

8 ответов

Лучший ответ

Вам необходимо использовать регулярное выражение для захвата группы и определить его как необработанную строку.

>>> re.search(r'([a-z])\1', 'ugknbfddgicrmopn').group()
'dd'
>>> [i+i for i in re.findall(r'([a-z])\1', 'abbbbcppq')]
['bb', 'bb', 'pp']

Или

>>> [i[0] for i in re.findall(r'(([a-z])\2)', 'abbbbcppq')]
['bb', 'bb', 'pp']

Обратите внимание, что re.findall здесь должен возвращать список кортежей с символами, которые соответствуют первой группе в качестве первого элемента и второй группе в качестве второго элемента. Для нашего случая символов в первой группе будет достаточно, поэтому я упомянул i[0].

50
Avinash Raj 14 Дек 2015 в 09:06

Как Pythonic способ Вы можете использовать функцию zip в понимании списка:

>>> s = 'abbbcppq'
>>>
>>> [i+j for i,j in zip(s,s[1:]) if i==j]
['bb', 'bb', 'pp']

Если вы имеете дело с большой строкой, вы можете использовать функцию iter() для преобразования строки в итератор и использовать itertols.tee() для создания двух независимых итераторов, а затем вызвать функцию next на втором итераторе. первый элемент и вызовите класс zip (в Python 2.X используйте itertools.izip(), который возвращает итератор) с этими итераторами.

>>> from itertools import tee
>>> first = iter(s)
>>> second, first = tee(first)
>>> next(second)
'a'
>>> [i+j for i,j in zip(first,second) if i==j]
['bb', 'bb', 'pp']

Тест с RegEx рецептом:

# ZIP
~ $ python -m timeit --setup "s='abbbcppq'" "[i+j for i,j in zip(s,s[1:]) if i==j]"
1000000 loops, best of 3: 1.56 usec per loop

# REGEX
~ $ python -m timeit --setup "s='abbbcppq';import re" "[i[0] for i in re.findall(r'(([a-z])\2)', 'abbbbcppq')]"
100000 loops, best of 3: 3.21 usec per loop

После вашего последнего редактирования, как упомянуто в комментарии, если вы хотите сопоставить только одну пару b в строках типа "abbbcppq", вы можете использовать finditer(), который возвращает итератор сопоставленных объектов, и извлекает результат с помощью group() метода:

>>> import re
>>> 
>>> s = "abbbcppq"
>>> [item.group(0) for item in re.finditer(r'([a-z])\1',s,re.I)]
['bb', 'pp']

Обратите внимание, что re.I является флагом IGNORECASE , который заставляет RegEx также соответствовать заглавным буквам.

32
Kasramvd 15 Дек 2015 в 06:24

Это довольно легко без регулярных выражений:

In [4]: [k for k, v in collections.Counter("abracadabra").items() if v==2]
Out[4]: ['b', 'r']
5
Dima Tisnek 14 Дек 2015 в 11:04
>>> l = ['ug', 'kn', 'bf', 'dd', 'gi', 'cr', 'mo', 'pn']
>>> import re
>>> newList = [item for item in l if re.search(r"([a-z]{1})\1", item)]
>>> newList
['dd']
0
Mayur Koshti 14 Дек 2015 в 07:13

"или, может быть, есть несколько лучших способов"

Так как регулярные выражения часто неправильно понимаются следующим разработчиком, сталкивающимся с вашим кодом (возможно, даже с вами), и так как проще! = Короче,

Как насчет следующего псевдокода:

function findMultipleLetters(inputString) {        
    foreach (letter in inputString) {
        dictionaryOfLettersOccurrance[letter]++;
        if (dictionaryOfLettersOccurrance[letter] == 2) {
            multipleLetters.add(letter);
        }
    }
    return multipleLetters;
}
multipleLetters = findMultipleLetters("ugknbfddgicrmopn");
2
Lavi Avigdor 14 Дек 2015 в 07:48

Используя обратную ссылку, это очень просто:

import re
p = re.compile(ur'([a-z])\1{1,}')
re.findall(p, u"ugknbfddgicrmopn")
#output: [u'd']
re.findall(p,"abbbcppq")
#output: ['b', 'p']

Для получения дополнительной информации вы можете обратиться к аналогичному вопросу в perl: Регулярное выражение для соответствия любому символу, повторяемому более 10 раз

9
Community 23 Май 2017 в 10:29
A1 = "abcdededdssffffccfxx"

print A1[1]
for i in range(len(A1)-1):
    if A1[i+1] == A1[i]:
        if not A1[i+1] == A1[i-1]:
            print A1[i] *2
2
Kevin Guan 14 Дек 2015 в 08:56

Может быть, вы можете использовать генератор для достижения этой цели

def adj(s):
    last_c = None
    for c in s:
        if c == last_c:
            yield c * 2
        last_c = c

s = 'ugknbfddgicrmopn'
v = [x for x in adj(s)]
print(v)
# output: ['dd']
4
xhg 14 Дек 2015 в 07:18