如何匹配<a>标记之前的文本然后返回<a>节点?

时间:2019-12-15 00:49:50

标签: html regex parsing go

在以下情况下,我试图仅捕获第二种情况,即文本与useEffect(() => { let something = somethingelse; setSearchList(searchList => [...searchList, search]); }, [search]); 相匹配。目前,它捕获了这两种情况。

But I want this one here

这将输出:

package main import ( "bytes" "fmt" "io" "strings" "golang.org/x/net/html" ) func getTag(doc *html.Node, tag string) []*html.Node { var nodes []*html.Node var crawler func(*html.Node) crawler = func(node *html.Node) { if node.Type == html.ElementNode && node.Data == tag { nodes = append(nodes, node) return } for child := node.FirstChild; child != nil; child = child.NextSibling { crawler(child) } } crawler(doc) return nodes } func main() { doc, _ := html.Parse(strings.NewReader(testHTML)) nodes := getTag(doc, "a") var buf bytes.Buffer w := io.Writer(&buf) for i, node := range nodes { html.Render(w, node) if i < (len(nodes) - 1) { w.Write([]byte("\n")) } } fmt.Println(buf.String()) } var testHTML = `<html><body> I do not want this link here <a href="blah">link text</a> But I want this one here <a href="blah blah">more link text</a> </body></html>`

我想匹配<a href="blah">link text</a> <a href="blah blah">more link text</a>标记之前的特定文本,如果匹配,则返回<a>节点。例如,传递<a>并返回But I want this one here。有人告诉我不要用正则表达式解析html,但是现在我被卡住了。

1 个答案:

答案 0 :(得分:2)

您实际上已经很接近了,因为您已经在使用适当的解析器(html.Parse中的golang.org/x/net/html)。

这里的技巧是将页面的各个元素方便地绑定在一起,因此,您可以根据需要将现有的crawler代码与更高版本的过滤功能一起使用。 (您可以将过滤条件直接组合到搜寻器中。)

每个n *html.ElementNode之前都有一些东西,除非它是块中的初始元素(文档或第一个子节点的第一个),并且 something 位于n.PrevSibling中。如果其类型为html.TextNode,则具有以下形式的序列:

some text<a ...>thing</a>

,您可以检查上一个节点中的“一些文本”:

func wanted(re *regexp.Regexp, n *html.Node) bool {
    if n.PrevSibling == nil || n.PrevSibling.Type != html.TextNode {
        return false
    }
    return re.MatchString(n.PrevSibling.Data)
}

这不是完美的,因为您可能拥有例如:

text <font></font> broken <font></font>up<a href="lastlink">last link</a>

,当您可能应该将文本放到up中并将其传递给匹配器时,代码将尝试与字符串text broken up进行匹配。查看更完整的示例here