RegExを使用して文字列に2つの文字が2回現れるかどうかをキャッチしようとしています(または、もっと良い方法がありますか?)。たとえば、私の文字列は次のとおりです。
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
を2回キャッチします。
abbbbcppq
^^^^ ^^
したがって、出力は次のとおりです。
['bb', 'bb', 'pp']
キャプチャグループベースの正規表現を使用し、正規表現を生の文字列として定義する必要があります。
>>> 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
は、最初のグループが最初の要素として、2番目のグループが2番目の要素として一致する文字を含むタプルのリストを返します。私たちの場合、最初のグループ内の文字で十分なので、i[0]
。
Pythonの方法として、リスト内包内でZip
関数を使用できます。
_>>> s = 'abbbcppq'
>>>
>>> [i+j for i,j in Zip(s,s[1:]) if i==j]
['bb', 'bb', 'pp']
_
大きな文字列を処理する場合は、iter()
関数を使用して文字列をイテレータに変換し、itertols.tee()
を使用して2つの独立したイテレータを作成し、next
2番目のイテレータの関数は最初のアイテムを消費し、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
_
_"abbbcppq"
_のような文字列内のb
の1つのペアのみに一致させたい場合は、コメントに記載されている最後の編集後に、一致したオブジェクトの反復子を返す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が大文字にも一致することに注意してください。
後方参照を使用すると、非常に簡単です。
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回以上繰り返される任意の文字に一致する正規表現
正規表現がなくても簡単です。
In [4]: [k for k, v in collections.Counter("abracadabra").items() if v==2]
Out[4]: ['b', 'r']
たぶん、あなたはこれを達成するためにジェネレータを使用することができます
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
「または、もっと良い方法があるかもしれません」
正規表現は、次の開発者があなたのコード(あなたかもしれません)に出会うと誤解されることが多いため、より単純な!=より短いため、
次の擬似コードはどうですか:
function findMultipleLetters(inputString) {
foreach (letter in inputString) {
dictionaryOfLettersOccurrance[letter]++;
if (dictionaryOfLettersOccurrance[letter] == 2) {
multipleLetters.add(letter);
}
}
return multipleLetters;
}
multipleLetters = findMultipleLetters("ugknbfddgicrmopn");
>>> 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']