我将解释你的代码发生了什么:import re
file = open('f1.txt')
fixed = open('fnew.txt','w')
text = file.read()
match = re.compile('<.>')
for unwanted in text:
fixed_doc = match.sub(r' ',text)
fixed.write(fixed_doc)
指令text = file.read()创建一个名为text、类型为string的对象
请注意,我使用粗体字符来表示对象,使用text来表示该对象的name==标识符。
作为指令for unwanted in text:的结果,标识符unwanted被连续分配给文本对象引用的每个字符。
此外,re.compile('<.>')创建一个类型为RegexObject(我个人称之为compiled)的对象regex或简单地regex,<.>只是regex模式。
您将这个编译好的regex对象分配给标识符match:这是一个非常糟糕的做法,因为match已经是regex对象方法的名称,而且是您特别创建的方法的名称,因此您可以无误地编写match.matchmatch也是re模块的函数名。
为满足您的特殊需要而使用这个名称是非常混乱的。你必须避免那样。
使用file作为文件f1的文件处理程序的名称也有同样的缺陷。file已经是该语言中使用的标识符,必须避免它。
好吧。现在定义了这个名为match的错误对象,指令fixed_doc = match.sub(r' ',text)用替换的r' '替换了文本中的regexmatch找到的所有匹配项
注意,写r' '而不是仅仅写' '是完全多余的,因为' '中绝对没有需要转义的内容。在正则表达式问题中,每当需要编写字符串时,一些焦虑的人都会编写原始字符串,这是一种时尚。
由于其模式<.>,其中点符号表示“贪婪地吃掉位于之间的每个字符,除非它是一个换行符”,因此文本中通过match捕获的事件是每一行,直到最后一行>。
由于名称unwanted没有出现在该指令中,因此对文本的每个字符执行的操作是相同的,一个接一个。也就是说:没什么有趣的。
要分析程序的执行,您应该在代码中放置一些打印指令,以便理解发生了什么。例如,如果您执行print repr(fixed_doc),您将看到此文件的重复打印:' \n \n \n '。就像我说的:没什么有趣的。
代码中还有一个默认值:打开文件,但不关闭它们。必须关闭文件,否则可能会发生一些奇怪的现象,在我意识到这一需要之前,我亲自观察了我的一些代码。有些人假装这不是强制性的,但这是假的。
顺便说一下,打开和关闭文件的更好方式是使用with语句。它做所有的工作你不用担心。
是的。
所以,现在我可以为您的第一个问题建议一个代码:import re
def ripl(mat=None,li = []):
if mat==None:
li[:] = []
return
if mat.group(1):
li.append(mat.span(2))
return ''
elif mat.span() in li:
return ''
else:
return mat.group()
r = re.compile('[^>]+>'
'|'
']+)>(?=.*?(\\1>))',
re.DOTALL)
text = '''
George Washington
Joe Taylor
'''
print '1------------------------------------1'
print text
print '2------------------------------------2'
ripl()
print r.sub(ripl,text)
print '3------------------------------------3'
结果1------------------------------------1
George Washington
Joe Taylor
2------------------------------------2
George Washington
Joe Taylor
3------------------------------------3
原则如下:
当regex检测到标记时,
-如果是结束标记,则匹配
-如果它是开始标记,则仅当文本中的某个位置有相应的结束标记时,它才匹配
对于每个匹配,正则表达式的方法sub()调用函数ripl()来执行替换。
如果匹配的是一个开始标记(在文本的某个地方后面必须跟有相应的结束标记,通过正则表达式的构造),那么ripl()返回''。
如果匹配的是结束标记,ripl()返回''只有在检测到文本中的此结束标记之前是前一个开始标记的对应结束标记的情况下。这可以通过在列表中记录每次检测到并匹配开始标记时每个对应结束标记的范围来实现。
那个录制列表li被定义为默认参数,以便它始终与函数每次调用时使用的列表相同ripl()(请将默认参数的函数引用到undertsand,因为它很微妙)。
由于将li定义为接收默认参数的参数,列表对象li将保留分析多个文本时记录的所有跨距,以防连续分析多个文本。为了避免列表li保留过去文本匹配的范围,有必要使列表为空。我编写这个函数是为了让第一个参数定义为一个默认参数None:它允许在regex的sub()方法中使用它之前无需参数就可以调用ripl()
那么,在使用它之前,必须考虑编写ripl()。
是的。
如果要删除文本的换行符以获得问题中显示的精确结果,则必须将代码修改为:import re
def ripl(mat=None,li = []):
if mat==None:
li[:] = []
return
if mat.group(1):
return ''
elif mat.group(2):
li.append(mat.span(3))
return ''
elif mat.span() in li:
return ''
else:
return mat.group()
r = re.compile('( *\n *)'
'|'
'[^>]+>'
'|'
']+)>(?=.*?(\\2>)) *',
re.DOTALL)
text = '''
George Washington
Joe Taylor
'''
print '1------------------------------------1'
print text
print '2------------------------------------2'
ripl()
print r.sub(ripl,text)
print '3------------------------------------3'
结果1------------------------------------1
George Washington
Joe Taylor
2------------------------------------2
George WashingtonJoe Taylor
3------------------------------------3