问题第1部分

我得到了这个文件f1:

<something @37>
<name>George Washington</name>
<a23c>Joe Taylor</a23c>
</something @37>

我想重新编译它,看起来像是f1 :(带空格)
George Washington Joe Taylor

我尝试了这段代码,但是有点删除了所有内容:
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)

我的猜测是re.compile行,但是我不太确定该怎么做。我不应该使用第三方扩展。有任何想法吗?
问题第2部分

关于比较从Alfe获得此代码的2个文件,我有一个不同的问题:
from collections import Counter

def test():
    with open('f1.txt') as f:
        contentsI = f.read()
    with open('f2.txt') as f:
        contentsO = f.read()

    tokensI = Counter(value for value in contentsI.split()
                        if value not in [])
    tokensO = Counter(value for value in contentsO.split()
                        if value not in [])
    return not (tokensI - tokensO) and not (set(tokensO) - set(tokensI))

是否可以在“如果不在[]中的值”部分中实现re.compile和re.sub?

最佳答案

我将解释您的代码会发生什么:

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的字符串类型的对象文本
请注意,我使用粗体字符文本表示对象,并使用text表示此对象的名称== IDENTIFIER。
作为指令for unwanted in text:的结果,标识符unwanted依次分配给文本对象引用的每个字符。

此外,re.compile('<.*>')创建一个类型为RegexObject(我个人称其为已编译)的对象regex或简称为regex,<.*>仅是regex模式)。
您将已编译的正则表达式对象分配给标识符match:这是一个非常糟糕的做法,因为match通常已经是正则表达式对象的方法的名称,尤其是您创建的正则表达式对象的方法的名称,因此您可以编写match.match而不会出错。match也是 re 模块的功能名称。
将此名称用于您的特定需求非常令人困惑。您必须避免这种情况。

使用file作为文件f1的文件处理程序的名称也存在相同的缺陷。 file已经是该语言使用的标识符,您必须避免使用它。

出色地。现在定义了这个名字不正确的匹配对象,指令fixed_doc = match.sub(r' ',text)用替换r' '替换了正规表达式匹配文本中找到的所有匹配项。
请注意,编写r' '而不是' '完全是多余的,因为' '中绝对没有需要转义的内容。某些急于每次在正则表达式问题中编写字符串时都写原始字符串的人是一种时尚。

由于它的<.+>模式,其中点符号的意思是“贪婪地吃掉<>之间的每个字符(除非它是换行符)”,所以匹配在文本中捕获的事件是每行,直到最后一个>它。
由于名称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 = '''<something @37>
<name>George <wxc>Washington</name>
<a23c>Joe </zazaza>Taylor</a23c>
</something @37>'''
print '1------------------------------------1'
print text
print '2------------------------------------2'
ripl()
print r.sub(ripl,text)
print '3------------------------------------3'

结果
1------------------------------------1
<something @37>
<name>George <wxc>Washington</name>
<a23c>Joe </zazaza>Taylor</a23c>
</something @37>
2------------------------------------2

George <wxc>Washington
Joe </zazaza>Taylor

3------------------------------------3

原理如下:

当正则表达式检测到标签时,
-如果是结束标记,则表示匹配
-如果是开始标记,则仅在文本中更远的地方有相应的结束标记时才匹配
对于每个匹配项,正则表达式sub()r方法调用函数ripl()进行替换。
如果匹配带有开始标记(必须在文本中的后面加上相应的结束标记,再通过正则表达式进行构造),则ripl()返回''
如果匹配与结束标记匹配,则仅当此结束标记先前已在文本中被检测到为先前开始标记的相应结束标记时,ripl()才返回''。可以通过在列表 li 中记录每次检测到并匹配起始标签的每个相应结束标签的跨度来实现。

记录列表 li 被定义为默认参数,以便始终与每次调用ripl()函数时使用的列表相同(请注意,默认参数对undertsand的功能,因为它很细微)。
由于将li定义为接收默认参数的参数,因此列表对象 li 将保留在分析多个文本时记录的所有跨度,以防连续分析多个文本。为了避免列表 li 保留过去的文本匹配范围,有必要将列表清空。我编写该函数是为了使用默认参数None定义第一个参数:允许在不使用正则表达式的ripl()方法中使用它的情况下调用不带参数的sub()
然后,必须先考虑编写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 = '''<something @37>
<name>George <wxc>Washington</name>
<a23c>Joe </zazaza>Taylor</a23c>
</something @37>'''
print '1------------------------------------1'
print text
print '2------------------------------------2'
ripl()
print r.sub(ripl,text)
print '3------------------------------------3'

结果
1------------------------------------1
<something @37>
<name>George <wxc>Washington</name>
<a23c>Joe </zazaza>Taylor</a23c>
</something @37>
2------------------------------------2
George <wxc>WashingtonJoe </zazaza>Taylor
3------------------------------------3

关于Python:重新编译和重新订阅,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18457101/

10-12 20:41