子串任何类型的 HTML 字符串

Substring any kind of HTML String

我需要将任何类型的 html 代码(字符串)划分为一个标记列表。 例如:

"<abc/><abc/>" #INPUT
["<abc/>", "<abc/>"] #OUTPUT

"<abc comfy><room /></abc> <br /> <abc/> " # INPUT
 ["<abc comfy><room /></abc>", "<br />", "<abc/>"] # OUTPUT

"""<meta charset="utf-8" /><title> test123 </title><meta name="test" content="index,follow" /><meta name="description" content="Description" /><link rel="stylesheet" href="../layout/css/default.css" />""" # INPUT
[
     '<meta charset="utf-8" />',
     "<title> test123 </title>",
     '<meta name="test" content="index,follow" />',
     '<meta name="description" content="Description123" />',
     '<link rel="stylesheet" href="../xx/css/default.css" />',
 ] # OUTPUT

我尝试做的事情:

def split(html: str) -> List[str]:
     if html == "":
         return []

     delimiter = "/>"
     split_name = html.split(" ", maxsplit=1)[0]
     name = split_name[1:]

     delimited_list = [character + delimiter for character in html.split(delimiter) if character]

     rest = html.split(" ", maxsplit=1)[1]

     char_delim = html.find("</")

     ### Help
     print(delimited_list)
     return delimited_list

我的输出:

['<abc/>', '<abc/>']
['<abc comfy><room />', '</abc> <br />', ' <abc/>', ' />']

['<meta charset="utf-8" />', '<title> test123</title><meta name="test" content="index,follow" />', '<meta name="description" content="Description123" />', '<link rel="stylesheet" href="../xx/css/default.css" />']

所以我尝试在“/>”处拆分,这对第一种情况有效。然后我尝试了几件事。试图识别“名称”,所以html字符串的第一个标识符像“abc”。

你们知道如何继续吗?

谢谢!

问候 尼克

您将需要一个堆栈数据结构并遍历字符串,将开始标签的位置压入堆栈,然后当您遇到结束标签时,我们假设:

  1. 它的名字匹配从栈顶位置开始的标签的名字

  2. 是自闭标签

我们还维护一个 result 列表来保存已解析的子字符串。

对于1),我们简单地弹出栈顶位置,并将从这个弹出位置切片到结束标记结束的子字符串保存到result列表中。

对于2),我们不修改栈,只将自闭标签子串保存到result列表中。

遇到任何标签(打开,关闭,自关闭)后,我们将迭代器(a.k.a。当前位置指针)向前移动该标签的长度(从<到相应的>).

如果从迭代器向前切片的 html 字符串不匹配(从头开始)任何标签,那么我们只需将迭代器向前移动一个(我们爬行直到我们可以再次匹配标签)。

这是我的尝试:

import re

def split(html):
    if html == "":
        return []

    openingTagPattern = r"<([a-zA-Z]+)(?:\s[^>]*)*(?<!\/)>"
    closingTagPattern = r"<\/([a-zA-Z]+).*?>"
    selfClosingTagPattern = r"<([a-zA-Z]+).*?\/>"

    result = []
    stack = []

    i = 0
    while i < len(html):
        match = re.match(openingTagPattern, html[i:])
        if match: # opening tag
            stack.append(i) # push position of start of opening tag onto stack
    
            i += len(match[0])
            continue
        
        match = re.match(closingTagPattern, html[i:])
        if match: # closing tag
            i += len(match[0])
            result.append(html[stack.pop():i]) # pop position of start of corresponding opening tag from stack
            continue
        
        match = re.match(selfClosingTagPattern, html[i:])
        if match: # self-closing tag
            start = i
            i += len(match[0])
            result.append(html[start:i])
            continue
        
        i+=1 # otherwise crawl until we can match a tag
        
    return result # reached the end of the string

用法:

delimitedList = split("""<meta charset="utf-8" /><title> test123 </title><meta name="test" content="index,follow" /><meta name="description" content="Description" /><link rel="stylesheet" href="../layout/css/default.css" />""")

for item in delimitedList:
    print(item)

输出:

<meta charset="utf-8" />
<title> test123 </title>
<meta name="test" content="index,follow" />
<meta name="description" content="Description" />
<link rel="stylesheet" href="../layout/css/default.css" />

参考文献:

openingTagPattern 的灵​​感来自@Kobi 在这里的回答: