web-dev-qa-db-ja.com

文字列で「2回現れる1文字」を見つける

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']
56
Kevin Guan

キャプチャグループベースの正規表現を使用し、正規表現を生の文字列として定義する必要があります。

>>> 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]

50
Avinash Raj

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が大文字にも一致することに注意してください。

32
Kasrâmvd

後方参照を使用すると、非常に簡単です。

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
Gurupad Hegde

正規表現がなくても簡単です。

In [4]: [k for k, v in collections.Counter("abracadabra").items() if v==2]
Out[4]: ['b', 'r']
5
Dima Tisnek

たぶん、あなたはこれを達成するためにジェネレータを使用することができます

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
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
Mark White

「または、もっと良い方法があるかもしれません」

正規表現は、次の開発者があなたのコード(あなたかもしれません)に出会うと誤解されることが多いため、より単純な!=より短いため、

次の擬似コードはどうですか:

function findMultipleLetters(inputString) {        
    foreach (letter in inputString) {
        dictionaryOfLettersOccurrance[letter]++;
        if (dictionaryOfLettersOccurrance[letter] == 2) {
            multipleLetters.add(letter);
        }
    }
    return multipleLetters;
}
multipleLetters = findMultipleLetters("ugknbfddgicrmopn");
2
Lavi Avigdor
>>> 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