在 Python 中拆分标记上的文本

Split text on markup in Python

提问人:Aurélien Pierre 提问时间:8/9/2023 更新时间:9/29/2023 访问量:78

问:

我有以下一行文字:

<code>stuff</code> and stuff and $\LaTeX$ and <pre class="mermaid">stuff</pre>

使用 Python,我想分解标记实体以获取以下列表:

['<code>', 'stuff', '</code>', ' and stuff and $\\LaTeX$ ', '<pre class="mermaid">', 'stuff', '</pre>']

到目前为止,我使用了:

markup = re.compile(r"(<(?P<tag>[a-z]+).*>)(.*?)(<\/(?P=tag)>)")
text = '<code>stuff</code> and stuff and $\LaTeX$ and <pre class="mermaid">stuff</pre>'
words = re.split(markup, text)

但它产生:

['<code>', 'code', 'stuff', '</code>', ' and stuff and $\\LaTeX$ ', '<pre class="mermaid">', 'pre', 'stuff', '</pre>']

问题是该组被添加到列表中,因为它已被捕获。我捕获它只是为了获得最接近的结束标签。(?P=tag)

假设代码一次只处理一行,我怎么能在结果列表中摆脱它?

Python 正则表达式 拆分

评论

0赞 Luatic 8/9/2023
使用然后编写一个正则表达式来定义你认为一个“标记”的内容会更容易,而不是使用它需要你为分隔符编写一个丑陋的正则表达式。re.finditerre.split
0赞 Aurélien Pierre 8/9/2023
列表的目的是对纯文本和某些标签进行后处理,而丢弃其他一些标签,只返回匹配项,不会做我想做的事。re.finditer
1赞 bobble bubble 8/9/2023
甚至可能re.findall(r“<[^>]*>|[^<]+“,文本)

答:

1赞 Shub 8/9/2023 #1
s = r'<code>stuff</code> and stuff and $\LaTeX$ and <pre class="mermaid">stuff</pre>'

l = []

for i in range(len(s)):
    if s[i] == ">":
        l[-1] += s[i]
        l.append("")
    elif s[i] == "<":
        l.append("")
        l[-1] += s[i]
    else:
        l[-1] += s[i]
        
l.pop()
print(l)

输出:['<code>', 'stuff', '</code>', ' and stuff and $\\LaTeX$ and ', '<pre class="mermaid">', 'stuff', '</pre>']

3赞 ApaxPhoenix 8/9/2023 #2

您可以使用 which 是专为其设计的模块,它是 的同义词。xmlxml fileshtml

import xml.etree.ElementTree as ET

text = '<code>stuff</code> and stuff and $\LaTeX$ and <pre class="mermaid">stuff</pre>'

root = ET.fromstring(f'<root>{text}</root>')

result = []

for element in root:
    if element.tag:
        result.append(f'<{element.tag}>')
    if element.text:
        result.extend(element.text.split())
    if element.tail:
        result.append(element.tail)

print(result)
2赞 Luatic 8/9/2023 #3

RegEx 不适合解析 HTML。但是,它通常足以进行标记化。使用 ,标记化变成单行:re.finditer

list(map(lambda x: x.group(0), re.finditer(r"(?:<(?:.*?>)?)|[^<]+", s)))

解释:

  • 仅使用非捕获组;我们在这里不需要特定的捕获。(?:...)
  • 匹配“标签”(可能是无效的(只是符号),只能通过其开头识别,直到)或纯文本。<(?:.*?>)?<<>[^<]+

这将处理您的测试用例

s = '<code>stuff</code> and stuff and $\LaTeX$ and <pre class="mermaid">stuff</pre>'

正确地,生产

['<code>', 'stuff', '</code>', ' and stuff and $\\LaTeX$ and ', '<pre class="mermaid">', 'stuff', '</pre>']

但请注意,一个成熟的 HTML 分词器需要更复杂的常规语法来正确处理属性等。你最好使用现成的库来为你做标记解析(甚至只是标记化)。onclick = "console.log(1 < 2)"