我使用的是gedit regex插件(Python风格的正则表达式)。我想对一个组的反向引用做一些算术运算。
例如:
PART 1 DATA MODELS Chapter
2 Entity-Relationship Model 27
我想将其更改为
PART 1 DATA MODELS Chapter 25
2 Entity-Relationship Model 27
我的正则表达式是^(PART.*)\n(.*\s(\d+))\n
,我想用\1 (\3-2)\n\2\n
替换它,其中\3-2
是反向引用\3
减去2.但更换正则表达式是不对的。我想知道怎么做?谢谢!
答案 0 :(得分:8)
您可以传递re.sub
lambda函数,该函数为每个非重叠模式匹配取re.MatchObject
个对象并返回替换字符串。例如:
import re
print re.sub("(\d+)\+(\d+)",
lambda m: str(int(m.group(1))+int(m.group(2))),
"If 2+2 is 4 then 1+2+3+4 is 10")
打印
如果4是4则3 + 7是10
您可以轻松地将其应用于您的问题。
答案 1 :(得分:5)
以下代码作为示例对您提供的字符串执行所需操作。有一点是它非常特定于这一个字符串的格式。它无法管理字符串中的任何变化。它实际上仅限于这种类型的字符串格式。
import re
ss = '''PART 1 DATA MODELS Chapter
2 Entity-Relationship Model 27
The sun is shining
PART 1 DATA MODELS Chapter
13 Entity-Relationship Model 45
'''
regx = re.compile('^(PART.*)(\n(\d*).*\s(\d+)\n)',re.MULTILINE)
def repl(mat):
return ''.join((mat.group(1),' ',
str(int(mat.group(4))-int(mat.group(3))),
mat.group(2)))
for mat in regx.finditer(ss):
print mat.groups()
print
print regx.sub(repl,ss)
结果
('PART 1 DATA MODELS Chapter', '\n2 Entity-Relationship Model 27\n', '2', '27')
('PART 1 DATA MODELS Chapter', '\n13 Entity-Relationship Model 45\n', '13', '45')
PART 1 DATA MODELS Chapter 25
2 Entity-Relationship Model 27
The sun is shining
PART 1 DATA MODELS Chapter 32
13 Entity-Relationship Model 45
已编辑:我忘记了re.MULTILINE标志
答案 2 :(得分:3)
我不知道你可以在正则表达式中进行算术运算或其他计算。如果有一个支持它的正则表达式引擎,它会非常漂亮!但我的理解是,如果没有大幅减慢正则表达式引擎的速度,这将是不切实际的。
我认为您最好的选择是使用sub
正则表达式函数/方法:
re.sub(pattern, repl, string[, count, flags])
返回字符串 通过替换最左边的非重叠事件获得 替换repl中的字符串模式。如果找不到模式, string返回不变。 repl可以是字符串或函数;如果 它是一个字符串,其中的任何反斜杠转义都被处理。那就是\ n 转换为单个换行符,\ r \ n转换为a 换行,等等。诸如\ j之类的未知转义单独留下。 反序列,例如\ 6,将被匹配的子字符串替换 模式中的第6组。例如:
>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', ... r'static PyObject*\npy_\1(void)\n{', ... 'def myfunc():') 'static PyObject*\npy_myfunc(void)\n{'
如果repl是一个函数,那就是 要求每个非重叠的模式发生。功能 获取单个匹配对象参数,并返回替换 串。例如:
>>> def dashrepl(matchobj): ... if matchobj.group(0) == '-': return ' ' ... else: return '-' >>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 'pro--gram files' >>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE) 'Baked Beans & Spam'
模式可以是字符串或RE对象。
可选参数count是模式的最大数量 要被替换的事件; count必须是非负整数。如果 省略或为零,所有出现都将被替换。空的比赛 只有在与前一个匹配不相邻时才替换该模式, 所以sub('x *',' - ','abc')返回'-a-b-c - '。
除了描述的字符转义和反向引用 在上面,\ g将使用由名为group的组匹配的子字符串 name,由(?P ...)语法定义。 \ g使用了 相应的组号; \克LT 2 - ;因此相当于\ 2,但是 在诸如\ g< 2> 0的替换中不是模糊的。 \ 20会 解释为对第20组的引用,而不是对第2组的引用 后跟字面字符'0'。反向引用\ g< 0> 在RE匹配的整个子字符串中替换。
您可以将repl作为一个函数传递,该函数计算要替换回原始字符串的值。
答案 3 :(得分:1)
除非gedit是Python的超集,否则它将不允许在您尝试使用(\3-2)
时在replace-regex中进行操作。在任何情况下,\3
都是一个字符串,您需要先使用int()进行转换。
因此,您必须将其分解为单独的 re.search(...),计算插入的pageno,然后插入。
第二个问题是你没有匹配'2'的页面长度,你在=中硬编码了 - 你想要你的正则表达式从第二行的开头匹配吗?
(在任何情况下,你的多线匹配只会匹配PART之后的一行,如果这是你的意图。)
这里用普通的Python正则表达式实现:
for (chap,sect,page) in re.finditer(r'^(PART.*)\n(.*\s+(\d+))\n', input, re.M):
print chap, int(page)-2
print sect
(我试图将其包装为repl fn paginate_chapter(matchobj)
,但是无法让re.sub可靠地调用它...)