J'essaie d'attraper si une lettre qui apparaît deux fois dans une chaîne en utilisant RegEx (ou peut-être qu'il existe de meilleures façons?), Par exemple ma chaîne est:
ugknbfddgicrmopn
La sortie serait:
dd
Cependant, j'ai essayé quelque chose comme:
re.findall('[a-z]{2}', 'ugknbfddgicrmopn')
mais dans ce cas, il renvoie:
['ug', 'kn', 'bf', 'dd', 'gi', 'cr', 'mo', 'pn'] # the except output is `['dd']`
J'ai également un moyen d'obtenir la sortie attendue:
>>> l = []
>>> tmp = None
>>> for i in 'ugknbfddgicrmopn':
... if tmp != i:
... tmp = i
... continue
... l.append(i*2)
...
...
>>> l
['dd']
>>>
Mais c'est trop complexe ...
Si c'est 'abbbcppq'
, alors attraper seulement:
abbbcppq
^^ ^^
La sortie est donc:
['bb', 'pp']
Ensuite, si c'est 'abbbbcppq'
, attraper bb
deux fois:
abbbbcppq
^^^^ ^^
La sortie est donc:
['bb', 'bb', 'pp']
Vous devez utiliser la capture d'expression régulière basée sur un groupe et définir votre expression régulière en tant que chaîne brute.
>>> re.search(r'([a-z])\1', 'ugknbfddgicrmopn').group()
'dd'
>>> [i+i for i in re.findall(r'([a-z])\1', 'abbbbcppq')]
['bb', 'bb', 'pp']
ou
>>> [i[0] for i in re.findall(r'(([a-z])\2)', 'abbbbcppq')]
['bb', 'bb', 'pp']
Notez que , re.findall
ici devrait renvoyer la liste des tuples avec les caractères qui sont mis en correspondance par le premier groupe comme premier élément et le deuxième groupe comme deuxième élément. Pour nos cas, les caractères au sein du premier groupe seraient suffisants, j'ai donc mentionné i[0]
.
De manière Pythonique Vous pouvez utiliser la fonction Zip
dans une liste de compréhension:
>>> s = 'abbbcppq'
>>>
>>> [i+j for i,j in Zip(s,s[1:]) if i==j]
['bb', 'bb', 'pp']
Si vous avez affaire à une chaîne de grande taille, vous pouvez utiliser la fonction iter()
pour convertir la chaîne en itérateur et utiliser itertols.tee()
pour créer deux itérateurs indépendants, puis en appelant next
la fonction sur le deuxième itérateur consomme le premier élément et utilise l'appel à la classe Zip
(dans Python 2.X utilisez itertools.izip()
qui retourne un itérateur) avec cet itérateur) .
>>> 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
recette:# 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
Après votre dernière modification, comme indiqué dans le commentaire, si vous ne souhaitez faire correspondre qu’une paire de b
dans des chaînes comme "abbbcppq"
, Vous pouvez utiliser finditer()
qui renvoie un itérateur d’objets correspondants, et extrayez le résultat avec la méthode group()
:
>>> import re
>>>
>>> s = "abbbcppq"
>>> [item.group(0) for item in re.finditer(r'([a-z])\1',s,re.I)]
['bb', 'pp']
Notez que re.I
Est l'indicateur IGNORECASE qui fait que le RegEx correspond également aux lettres majuscules.
En utilisant la référence arrière, c'est très simple:
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']
Pour plus de détails, vous pouvez vous référer à une question similaire en Perl: Expression régulière pour correspondre à n'importe quel caractère répété plus de 10 fois
C'est assez facile sans expressions régulières:
In [4]: [k for k, v in collections.Counter("abracadabra").items() if v==2]
Out[4]: ['b', 'r']
Vous pouvez peut-être utiliser le générateur pour y parvenir
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']
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
"ou peut-être qu'il y a de meilleures façons"
Étant donné que l'expression régulière est souvent mal comprise par le prochain développeur pour rencontrer votre code (peut-être même vous), et puisque plus simple! = Plus court,
Que diriez-vous du pseudo-code suivant:
function findMultipleLetters(inputString) {
foreach (letter in inputString) {
dictionaryOfLettersOccurrance[letter]++;
if (dictionaryOfLettersOccurrance[letter] == 2) {
multipleLetters.add(letter);
}
}
return multipleLetters;
}
multipleLetters = findMultipleLetters("ugknbfddgicrmopn");