【问题标题】:Python: re.compile and re.subPython:重新编译和重新编译
【发布时间】:2013-08-27 04:43:19
【问题描述】:

问题第 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 行,但我不太确定如何处理它。我不应该使用第 3 方扩展。有什么想法吗?


问题第 2 部分

我有一个关于比较两个文件的不同问题,我从 Alfe 获得了这段代码:

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))

是否可以在'if value not in []'部分实现re.compile和re.sub?

【问题讨论】:

  • 你好。在第一个问题中,您是否打算删除所有看起来像标签的东西,或者真正定义标记语言元素的标签?我在正确和正确的意义上使用“元素”这个词,意思是“开始标签+元素内容+结束标签”。 - 此外,当您公开文件 f 的内容时,其中有行,也就是说其中有换行符。您显示为所需结果的是一个字符串,其中没有更多的换行符。这真的是你想要的还是你想保持线条的结构?
  • 您想对if value not in []) 表示什么?目前它没有任何意义,因为在无效列表中始终没有任何内容。作为文件比较,您希望做什么?不是很清楚

标签: python compilation compare


【解决方案1】:

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

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 来表示一个 OBJECT,并使用 text 来表示这个对象的名称 == IDENTIFIER。
作为指令for unwanted in text: 的结果,标识符unwanted 被连续分配给text 对象引用的每个字符。

此外,re.compile('&lt;.*&gt;') 创建了一个 RegexObject 类型的对象(我个人称其为 已编译)正则表达式或简称为 regex&lt;.*&gt; 只是 正则表达式模式)。
您将此编译的正则表达式对象分配给标识符match:这是一种非常糟糕的做法,因为match 通常已经是正则表达式对象的方法的名称,并且是您特别创建的方法的名称,因此您可以编写match.match 没有错误。
match 也是 re 模块的函数名称。
将此名称用于您的特殊需要是非常令人困惑的。你必须避免这种情况。

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

嗯。现在定义了这个名字不好的 ma​​tch 对象,指令fixed_doc = match.sub(r' ',text)text 中正则表达式 ma​​tch 找到的所有出现替换为替换r' '.
请注意,写r' ' 而不仅仅是写' ' 是完全多余的,因为' ' 中绝对没有任何东西需要转义。一些焦虑的人在每次必须在正则表达式问题中编写字符串时都编写原始字符串是一种时尚。

由于它的模式&lt;.+&gt; 中的点符号表示“贪婪地吃掉位于&lt;&gt; 之间的每个字符,除非它是换行符”,因此match 是每一行,直到其中的最后一个 &gt;
由于名称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

原理如下:

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

录制列表li被定义为默认参数,以便在每次调用函数ripl()时使用的列表始终相同(请参阅默认参数的功能理解,因为它很微妙)。
由于将li定义为接收默认参数的参数,列表对象li将保留在分析多个文本时记录的所有跨度,以防多个文本被连续分析。为了避免列表 li 保留过去文本匹配的范围,有必要使列表为空。我编写了该函数,以便使用默认参数 None 定义第一个参数:允许在正则表达式的 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 = '''<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

【讨论】:

  • @Duboe 请看我的回答。请注意,我在其中使用的替换字符是'',而不是空白' '
【解决方案2】:

您可以使用 Beautiful Soup 轻松做到这一点:

from bs4 import BeautifulSoup
file = open('f1.txt')
fixed = open('fnew.txt','w')

#now for some soup

soup = BeautifulSoup(file)

fixed.write(str(soup.get_text()).replace('\n',' '))

以上行的输出将是:

George Washington Joe Taylor

(至少这适用于你给我的样本)

对不起,我没看懂第 2 部分,祝你好运!

【讨论】:

  • 这很好,虽然我无法使用尚未包含的扩展:/但我可能会在未来的一些项目中使用它:)
【解决方案3】:

不需要重新编译

import re  

clean_string = ''  

with open('f1.txt') as f1:  
    for line in f1:  
        match = re.search('.+>(.+)<.+', line)  
        if match:  
            clean_string += (match.group(1))  
            clean_string += ' '  

print(clean_string) # 'George Washington Joe Taylor'

【讨论】:

    【解决方案4】:

    发现第一部分是缺少的“?”

    match = re.compile('<.*?>')
    

    成功了。


    无论如何,第二个问题仍然不确定。 :/

    【讨论】:

    • 这是一个过于简单的解决方案。例如 text = 'Atlantic &lt;--- this is an ocean. &lt;&lt;&lt;keep it&gt;&gt;&gt; \nBat &lt;--- this is an animal *remove it*' 的结果 re.sub('&lt;.+?&gt;','',text)'Atlantic &gt;&gt;\nBat &lt;--- this is an animal *remove it*' 。为了避免这种情况,我在回答中写了代码
    【解决方案5】:

    对于第 1 部分,请尝试以下代码 sn-p。但是,请考虑使用 Moe Jan 建议的诸如 beautifulsoup 之类的库

    import re
    import os
    def main():
        f = open('sample_file.txt')
        fixed = open('fnew.txt','w')
    
    
    
        #pattern = re.compile(r'(?P<start_tag>\<.+?\>)(?P<content>.*?)(?P<end_tag>\</.+?\>)')
        pattern = re.compile(r'(?P<start><.+?>)(?P<content>.*?)(</.+?>)')
        output_text = []
        for text in f:
            match = pattern.match(text)
            if match is not None:
                output_text.append(match.group('content'))
    
        fixed_content = ' '.join(output_text)
    
    
        fixed.write(fixed_content)
        f.close()
        fixed.close()
    
    if __name__ == '__main__':
        main()
    

    第 2 部分

    我并不完全清楚你在问什么 - 但我的猜测是你想做类似if re.sub(value) not in [] 的事情。但是请注意,在初始化Counter 实例之前,您只需调用一次re.compile。如果您澄清问题的第二部分会更好。

    实际上,我建议您使用内置的 Python diff 模块来查找两个文件之间的差异。使用这种方式比使用您自己的 diff 算法更好,因为 diff 逻辑经过了良好的测试并被广泛使用,并且不易受到由虚假换行符、制表符和空格字符导致的逻辑或程序错误的影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-06
      相关资源
      最近更新 更多