我有以下一行文字:
<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)
组被添加到列表中,因为它已被捕获。我捕获它只是为了获得最接近的结束标签。
假设代码一次只处理一行,我怎样才能在结果列表中删除它?
您可以使用
xml
,这是为xml files
设计的模块,与html
同义。
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)
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)"
之类的属性。您最好使用现成的库来为您进行标记解析(甚至只是标记化)。
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>']