使用re.findall()替换所有匹配项

gdo*_*371 11 python regex

使用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
Run Code Online (Sandbox Code Playgroud)

但是,这会产生以下错误:

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'
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮助我在最后一点语法中我需要用原始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
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误:

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()
Run Code Online (Sandbox Code Playgroud)

Pad*_*ham 13

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)
Run Code Online (Sandbox Code Playgroud)

  • 效果很好,谢谢。你能简单地告诉我 lambda 线正在做什么,以便我知道以供将来参考吗? (2认同)

Blc*_*ght 5

如果我正确理解了您的问题,那么您正在尝试用两个字符之间的百分号替换两个字符之间的引号。

有几种方法可以使用re.sub(re.findall根本不进行替换,因此您最初的尝试总是注定要失败)。

一种简单的方法是更改​​您的模式以分别对字母进行分组,然后使用包含反向引用的替换字符串:

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

另一种选择是使用替换函数而不是替换字符串。对于match文本中找到的每个匹配项,将使用一个对象调用该函数,其返回值是替换:

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

(可能还有很多其他实现 lambda 函数的方法。我喜欢字符串格式。)

但是,最好的方法可能是在您的模式中使用前瞻和后视,以确保您的引号在字母之间而不实际匹配这些字母。这使您可以使用普通字符串'%'作为替换:

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

这确实与其他版本的语义略有不同。文本 like'a"b"c'将替换两个引号,而之前的代码只会替换第一个。希望这是一个改进!