2015-12-14 61 views
56

我試圖捕捉如果在一個字符串使用正則表達式中出現兩次一個字母(?也許有一些更好的方法),例如我的字符串是:查找字符串「出現兩次,一個字母」

ugknbfddgicrmopn 

輸出將是:

dd 

不過,我想是這樣:

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

但在這種情況下,換貨政... RNS:

['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',然後catch:

abbbcppq 
^^ ^^ 

所以輸出:

['bb', 'pp'] 

然後,如果它是'abbbbcppq',抓bb兩次:

abbbbcppq 
^^^^ ^^ 

所以輸出:

['bb', 'bb', 'pp'] 
+15

您可以使用反向引用,['([AZ])\ 1'](https://regex101.com/r/wT7cA9/1 ) – Tushar

+3

你似乎期望 - 但不提 - 連續性,而且如果存在「ddd」,你就不會解釋你想要什麼。 – DSM

+0

@kevin如果信件出現超過兩次>>? –

回答

50

您需要使用捕捉基於組正則表達式和定義你的正則表達式爲原始字符串。

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

+0

@KevinGuan使用我的findall方法.. –

+0

Ohhhhh,重新閱讀答案後,我明白它現在是如何工作的。所以'([a-z])'抓住第一個字母,'\ 1'重複它。 :) –

+3

@KevinGuan ya,正好......'()'叫做捕獲組。因此'([a-z])'捕獲第一個字母,而後面的'\ 1'是第一個捕獲組的後向引用。所以'\ 1'指的是第一組匹配的所有字符。 –

32

作爲Python化方式您可以使用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 

上次編輯後在評論中提到,如果你想只匹配在像"abbbcppq"串1對b可以使用finditer()返回匹配對象的迭代器,並用group()方法提取結果:

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

請注意re.IIGNORECASE標誌,它使RegEx與大寫字母匹配。

+0

那麼,作爲我的編輯,我想'abbbc'的'bb'好吧,我知道這是我的另一個簡短版本的例子,我的輸出的例子不是我編輯的期望ry關於那個...... –

+0

@KevinGuan在這種情況下,你需要一種理解。 – Kasramvd

+0

那麼,如果使用'set',那麼它就不能像我在我的問題的評論中所說的那樣抓住'bb'兩次。 –

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

如果給出一個項目列表,有什麼用?這對其他字符串不起作用。 –

+0

我已經使用're.search'只適用於字符串。 –

+0

另外,它適用於其他字符串。就像在列表中添加項目'zz'那麼​​它會同時給出'dd'和'zz'。 –

4

也許你可以使用發電機來實現這一

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'] 
2
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 
+7

歡迎來到SO!在回答時,還要添加對代碼的解釋。 – Tushar

+0

在這種情況下,如果我有'ffff',那麼輸出將是'['dd','ss','ff','ff','ff']'。 –

+0

其實......這還是沒有抓住ff','ff'',正如我在評論中所說的那樣。 –

2

「也許有一些更好的辦法」

因爲regex往往是由未來開發商誤解遇到你的代碼(可即使是你), 由於更簡單!=更短,

下面的僞代碼如何?

function findMultipleLetters(inputString) {   
    foreach (letter in inputString) { 
     dictionaryOfLettersOccurrance[letter]++; 
     if (dictionaryOfLettersOccurrance[letter] == 2) { 
      multipleLetters.add(letter); 
     } 
    } 
    return multipleLetters; 
} 
multipleLetters = findMultipleLetters("ugknbfddgicrmopn"); 
5

這是很容易沒有正則表達式:

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

嗯...如果輸入是'abbbbcppq',則不起作用。也許問題因爲'if v == 2' :) –

+0

你的問題有點含糊不清:我們是在尋找所有出現不止一次的字母,還是隻在整個輸入中出現兩次的字母?這個答案對於後者是準確的,但是對於前者'[k for k,v in collections.Counter(「abbbbcppq」)。items()if v> 1]'會做。 – MartyMacGyver

相關問題