2015-09-19 72 views
4

使用re.findall()我設法返回字符串中正則表達式的多個匹配。然而,我返回的對象是字符串內的匹配列表。這不是我想要的。使用re.findall()替換所有匹配()

我想要的是用其他東西替換所有匹配。我試着使用類似的語法,你會在應用re.sub利用這樣做,因爲這樣:

import json 
import re 

regex = re.compile('([a-zA-Z]\"[a-zA-Z])', re.S) 

filepath = "C:\\Python27\\Customer Stuff\\Austin Tweets.txt" 

f = open(filepath, 'r') 
myfile = re.findall(regex, '([a-zA-Z]\%[a-zA-Z])', f.read()) 
print myfile 

然而,這產生了以下錯誤:

Traceback (most recent call last): 
    File "C:/Python27/Customer Stuff/Austin's Script.py", line 9, in <module> 
    myfile = re.findall(regex, '([a-zA-Z]\%[a-zA-Z])', f.read()) 
    File "C:\Python27\lib\re.py", line 177, in findall 
    return _compile(pattern, flags).findall(string) 
    File "C:\Python27\lib\re.py", line 229, in _compile 
    bypass_cache = flags & DEBUG 
TypeError: unsupported operand type(s) for &: 'str' and 'int' 

誰能幫助我的內最後一點我需要用原始Python對象內的其他東西替換所有匹配的語法?

編輯:

在符合意見和答案好評,這裏我想再轉一個正則表達式與另一:

import json 
import re 

regex = re.compile('([a-zA-Z]\"[a-zA-Z])', re.S) 
regex2 = re.compile('([a-zA-Z]%[a-zA-Z])', re.S) 

filepath = "C:\\Python27\\Customer Stuff\\Austin Tweets.txt" 

f = open(filepath, 'r') 
myfile = f.read() 
myfile2 = re.sub(regex, regex2, myfile) 
print myfile 

現在,這將產生以下錯誤:

Traceback (most recent call last): 
    File "C:/Python27/Customer Stuff/Austin's Script.py", line 11, in <module> 
    myfile2 = re.sub(regex, regex2, myfile) 
    File "C:\Python27\lib\re.py", line 151, in sub 
    return _compile(pattern, flags).sub(repl, string, count) 
    File "C:\Python27\lib\re.py", line 273, in _subx 
    template = _compile_repl(template, pattern) 
    File "C:\Python27\lib\re.py", line 258, in _compile_repl 
    p = sre_parse.parse_template(repl, pattern) 
    File "C:\Python27\lib\sre_parse.py", line 706, in parse_template 
    s = Tokenizer(source) 
    File "C:\Python27\lib\sre_parse.py", line 181, in __init__ 
    self.__next() 
    File "C:\Python27\lib\sre_parse.py", line 183, in __next 
    if self.index >= len(self.string): 
TypeError: object of type '_sre.SRE_Pattern' has no len() 
+0

如果要替換匹配項,請使用're.sub'。 –

+0

如何以及在哪裏使用re.sub()雖然?如果你嘗試在你從re.findall()創建的對象上使用它,這是一個匹配列表,而不是原始對象。 – gdogg371

+0

你想用什麼來代替它? –

回答

8
import re 

regex = re.compile('([a-zA-Z]\"[a-zA-Z])', re.S) 
myfile = 'foo"s bar' 
myfile2 = regex.sub(lambda m: m.group().replace('"',"%",1), myfile) 
print(myfile2) 
+0

這個工作很好,謝謝。你能不能簡單地通過lambda行說明我做什麼,所以我知道以後參考? – gdogg371

+1

@ gdogg371,m是一個匹配對象,所以我們只是使用.group來獲得在我們的例子中匹配的子串即'o「s',然後用百分號 –

+0

代替雙引號,lamda只允許我們在re.sub邏輯中使用未分配的函數? – gdogg371

2

正如評論中所建議的,使用re.sub()

myfile = re.sub(regex, replacement, f.read()) 

其中,替換是您的匹配將被替換的字符串。

3

如果我正確理解您的問題,您試圖用這些字符之間的百分號替換兩個字符之間的引號。

有幾種方法可以做到這一點與re.subre.findall根本沒有做替換,所以你最初的嘗試總是註定要失敗)。

一個簡單的方法是將字母分別改變你的模式組,然後用替換字符串,其中包括反向引用:

pattern = re.compile('([a-zA-Z])\"([a-zA-Z])', re.S) 
re.sub(pattern, r'\1%\2', text) 

另一種選擇是使用一個替代函數,而不是替換字符串。該功能將與match對象在文本中找到的每場比賽被調用,它的返回值是更換:

pattern = re.compile('[a-zA-Z]\"[a-zA-Z]', re.S) 
re.sub(pattern, lambda match: "{0}%{2}".format(*match.group()), text) 

(可能有很多實現lambda函數的其他方面,我喜歡的字符串格式化)

但是,可能最好的方法是在模式中使用向前看和向後看來確保引號在字母之間,而不實際匹配這些字母。這可讓您使用瑣碎的字符串'%'爲替換:

pattern = re.compile('(?<=[a-zA-Z])\"(?=[a-zA-Z])', re.S) 
re.sub(pattern, '%', text) 

這並不比其他版本略微不同的語義。像'a"b"c'這樣的文本將會替換兩個引號,而以前的代碼只會替換第一個。希望這是一個改進!

1

我發現使用函數來做這種類型的替換而不是lambda表達更清晰。它可以很容易地替換文本之前執行任何數量的匹配文本的轉換:

import re 

def replace_double_quote(match): 
    text = match.group() 
    return text.replace('"', '%') 

regex = re.compile('([a-zA-Z]\"[a-zA-Z])') 
myfile = 'foo"s bar and bar"s foo' 
regex.sub(replace_double_quote, myfile) 

這將返回foo%s bar and bar%s foo。請注意,它會取代所有匹配。