【问题标题】:Capture the last occurrence of a tag捕获标签的最后一次出现
【发布时间】:2010-06-24 06:12:49
【问题描述】:

我的文字是这样的:

<Story>
 <Sentence id="1"> some text </Sentence>   
 <Sentence id="2"> some text </Sentence>   
 <Sentence id="3"> some text </Sentence>   

我的任务是在最后一个&lt;/Sentence&gt; 之后插入一个结束标记&lt;/Story&gt;。在正文中,每个&lt;/Sentence&gt; 后跟3 个空格。我尝试使用正则表达式 &lt;/Sentence&gt;(?!.*&lt;Sentence) 捕获最后一个 &lt;/Sentence&gt; 并使用 re.DOTALL 。但它不工作。

实际使用的代码是
line = re.sub(re.compile('&lt;/Sentence&gt;(?!.*&lt;Sentence)',re.DOTALL),'&lt;/Sentence&gt;&lt;/Story&gt;',line)

请帮忙。谢谢。

【问题讨论】:

  • 你真的应该为此use a parser
  • @David @msw 对无效的 xml 使用解析器?解析器在看到格式不正确的 xml 文档时不会抛出异常吗?
  • 好点,有些可以,但有些可以识别丢失的标签并自动添加。我想这取决于上下文。即便如此,当解析器抛出异常时,它可能包含无效标记的位置,这将是插入&lt;/Story&gt; 标记的位置。
  • HTML Tidy 和 BeautifulSoup 都是专门为处理格式错误的标记而设计的。
  • 用 Regex 解析 XML 听起来很简单,但除非使用 Regex 的好处超过不使用库的负面影响,否则不应该这样做。

标签: python xml regex last-occurrence


【解决方案1】:

生成整个文件的代码是否相同 - 如果是,则使用 xml 库生成它,然后所有标签都将正确嵌套 - 如果不修复生成它的代码,使其成为有效的 XML。

正则表达式和 xml 不能很好地结合在一起。

【讨论】:

  • 我使用的代码会生成一堆句子标签。我试图简单地放置一个根标签,以便它成为一个有效的 xml。放置&lt;Story 标签不是出价交易。我被它的结束标签卡住了。
  • @afs: 某些原因你不能使用'&lt;Story&gt;' + sentences + '&lt;/Story&gt;'?
【解决方案2】:

你真的应该使用像BeautifulSoup 这样的解析器来完成这项工作。 BeautifulSoup 可以解析非常不正确的 HTML/XML 并尝试使它们看起来正确。您的代码可能如下所示(我假设您在不正确的 Story 标记之前和之后都有一些标记,否则您将遵循 David 评论中的建议):

from BeautifulSoup import BeautifulStoneSoup

html = '''
<Document>
<PrevTag></PrevTag>
<Story>
 <Sentence id="1"> some text </Sentence>   
 <Sentence id="2"> some text </Sentence>   
 <Sentence id="3"> some text </Sentence>
<EndTag></EndTag>
</Document> 
'''
# Parse the document:
soup = BeautifulStoneSoup(html)

看看 BeautifulSoup 是如何解析它的:

print soup.prettify()

#<document>
# <prevtag>
# </prevtag>
# <story>
#  <sentence id="1">
#   some text
#  </sentence>
#  <sentence id="2">
#   some text
#  </sentence>
#  <sentence id="3">
#   some text
#  </sentence>
#  <endtag>
#  </endtag>
# </story>
#</document>

请注意,BeautifulSoup 在围绕它的标签(文档)关闭之前关闭了故事,因此您必须将结束标签移动到最后一句话旁边。

# Find the last sentence:
last_sentence = soup.findAll('sentence')[-1]

# Find the Story tag:
story = soup.find('story')

# Move all tags after the last sentence outside the Story tag:
sib = last_sentence.nextSibling
while sib:
    story.parent.append(sib.extract())
    sib = last_sentence.nextSibling

print soup.prettify()

#<document>
# <prevtag>
# </prevtag>
# <story>
#  <sentence id="1">
#   some text
#  </sentence>
#  <sentence id="2">
#   some text
#  </sentence>
#  <sentence id="3">
#   some text
#  </sentence>
# </story>
# <endtag>
# </endtag>
#</document>

最终结果应该正是您想要的。请注意,此代码假定文档中只有一个 Story——如果没有,则应稍作修改。祝你好运!

【讨论】:

    【解决方案3】:

    如果您只需要找到标记的最后一次出现,您可以:

    reSentenceClose= re.compile('</Sentence> *')
    match= None
    for match in reSentenceClose.finditer(your_text):
        pass
    
    if match: # it was found
        print match.end() # the index in your_text where the pattern was found
    

    【讨论】:

      【解决方案4】:

      为什么不匹配所有三个(或多个)&lt;Sentence&gt; 元素并使用组引用将它们重新插入?

      re.sub(r'(?:(\r?\n) *<Sentence.*?</Sentence> *)+',
             r'$0$1</Story>',
             line)
      

      【讨论】:

        猜你喜欢
        • 2020-12-16
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多