首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python: re.compile和re.sub

Python: re.compile和re.sub
EN

Stack Overflow用户
提问于 2013-08-27 04:43:19
回答 5查看 45.6K关注 0票数 18

问题第1部分

我拿到了这个文件f1

代码语言:javascript
复制
<something @37>
<name>George Washington</name> 
<a23c>Joe Taylor</a23c>
</something @37>

我想re.compile它看起来像f1:(带空格)

代码语言:javascript
复制
George Washington Joe Taylor

我尝试过这段代码,但它删除了所有内容:

代码语言:javascript
复制
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的代码的文件,我有一个不同的问题:

代码语言:javascript
复制
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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-08-27 11:18:39

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

代码语言:javascript
复制
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来表示对象,使用text表示该对象的名称==标识符。

作为指令for unwanted in text:的结果,标识符unwanted依次分配给由文本对象引用的每个字符。

此外,re.compile('<.*>')还创建了一个类型为RegexObject的对象(我个人称之为regex ) regex或简单的regex,<.*>只是regex模式。

您可以将这个已编译的regex对象分配给标识符match:这是一个非常糟糕的实践,因为match通常已经是regex对象的方法的名称,特别是您创建的方法的名称,因此您可以在没有错误的情况下编写match.match

match也是re模块函数的名称。

使用这个名称来满足您的特殊需要是非常令人困惑的。你必须避免那样做。

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

井。现在定义了这个名不详的匹配对象,指令fixed_doc = match.sub(r' ',text)用替换r' '替换了regex matchtext中发现的所有事件。

请注意,编写r' '完全是多余的,而不仅仅是' ',因为' '中绝对没有什么需要转义的。有些人在正则表达式问题中每次写字符串时都会写原始字符串,这是一种狂热的现象。

由于其模式<.+>中的点符号意味着“贪婪地吃掉<>之间的每一个字符,除非它是换行符”,因此match在文本中所捕捉到的每一行都是一行,直到最后一行为止。

由于名称unwanted没有出现在该指令中,因此对文本中的每个字符进行的操作都是相同的,一个接一个。这就是说:没什么有趣的。

要分析程序的执行情况,您应该在代码中添加一些打印指令,以便了解发生了什么。例如,如果您执行print repr(fixed_doc),您将看到以下内容的重复打印:' \n \n \n '。就像我说的:没什么有趣的。

您的代码中还有一个默认设置:打开文件,但不关闭它们。关闭文件是强制性的,否则可能会发生一些奇怪的现象,在我意识到这一点之前,我在我的一些代码中亲自观察到了这些现象。有些人假装这不是强制性的,但这是假的。

顺便说一下,打开和关闭文件的更好方式是使用with语句。你不用担心它就能完成所有的工作。

所以,现在我可以为你的第一个问题提出一个代码:

代码语言:javascript
复制
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'

结果

代码语言:javascript
复制
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

原则如下:

当正则表达式检测到标签时,

  • 如果它是一个结束标记,它就匹配--如果它是一个开始标记,那么只有当文本中有一个相应的结束标记时,它才匹配。 对于每个匹配,regex r的方法ripl()调用函数ripl()来执行替换。 如果匹配有一个开始标记(在文本中的某个地方,后面有相应的结束标记,通过regex的构造),那么ripl()返回''。 如果匹配是带有结束标记,则只有在以前检测到文本中的结束标记是前一个开始标记的对应结束标记时,ripl()才返回''。这可以通过在list li中记录每个对应的结束标记的跨度,每次检测到并匹配开始标记来实现。

recording list li被定义为默认参数,以便它总是在函数ripl()的每个调用中使用的相同的列表(请将默认参数的函数引用到undertsand,因为它很微妙)。

由于将li定义为接收默认参数的参数,list对象li将保留在分析多个文本时记录的所有跨度,以防连续分析多个文本。为了避免list li保留过去文本匹配的范围,有必要使列表为空。我编写了函数,以便使用默认参数None定义第一个参数:它允许在正则表达式的sub()方法中使用参数之前调用不带参数的ripl()

然后,在使用ripl()之前,必须考虑编写它。

如果要删除文本的换行符以获得问题中显示的准确结果,则必须将代码修改为:

代码语言:javascript
复制
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'

结果

代码语言:javascript
复制
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
票数 38
EN

Stack Overflow用户

发布于 2013-08-27 05:22:45

你可以用美丽的汤很容易做到这一点:

代码语言:javascript
复制
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',' '))

上述项目的产出如下:

代码语言:javascript
复制
George Washington Joe Taylor

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

对不起,我不明白第二部分,祝你好运!

票数 3
EN

Stack Overflow用户

发布于 2021-12-08 23:11:03

不需要re.compile

代码语言:javascript
复制
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'
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18457101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档