Go語言聖經練習5.1-5.4

前言

網上找不到5.1的解答參考,所以只能手動寫了一個。僅供參考。
補充5.2到5.4

題目

練習 5.1:修改findlinks代碼中遍歷n.FirstChild鏈表的部分,將循環調用visit,改成遞歸調用。
練習 5.2: 編寫函數,記錄在HTML樹中出現的同名元素的次數。
練習 5.3: 編寫函數輸出所有text結點的內容。注意不要訪問

代碼

package main

import (
	"fmt"
	"os"
	"io"
	"golang.org/x/net/html"
	"html/template"
	"log"
)

type NodeCount map[string]int 

const templ = `
--------------------------------------
|           HTML NODES COUNT         |
--------------------------------------
|                                    |
{{- range $key, $value := . }}
|  Type: {{ $key | printf "%-15s" }} Count: {{ $value | printf "%-4d" }} |
{{- end }}
|                                    |
--------------------------------------
`

func (nc NodeCount) Fprint(w io.Writer) {
	t := template.Must(template.New("escape").Parse(templ))
	if err := t.Execute(w, nc); err != nil {
		log.Fatal(err)
	}
	
}
func main() {
	doc, err := html.Parse(os.Stdin)
	if err != nil {
		fmt.Fprintf(os.Stderr, "findlinks1: %v\n", err)
		os.Exit(1)
	}
	for _, link := range visit(nil, doc) {
		fmt.Println(link)
	}
	// 5.2 output
	nodeCount := NodeCount{}
	count(&nodeCount, doc)
	nodeCount.Fprint(os.Stdout)
	// 5.3 output
	for _, text := range visitText(nil, doc) {
		fmt.Println(text)
	}
	// 5.4 output
	for _, link := range visitExtend(nil, doc) {
		fmt.Println(link)
	}
}

// 5.1 visit appends to links each link found in n and returns the result.
func visit(links []string, n *html.Node) []string {
	if n == nil {
		return links 
	}
	
	if n.Type == html.ElementNode && n.Data == "a" {
		for _, a := range n.Attr {
			if a.Key == "href" {
				links = append(links, a.Val)
			}
		}
	}
	/* for c := n.FirstChild; c != nil; c = c.NextSibling {
		links = visit(links, c)
	} */
	links = visit(links, n.FirstChild)
	links = visit(links, n.NextSibling)
	return links
}

// 5.2 
func count(nc *NodeCount, n *html.Node) {
	if n == nil {
		return 
	}
	if n.Type == html.ElementNode {
		(*nc)[n.Data]++
	}
	count(nc, n.FirstChild)
	count(nc, n.NextSibling)
}

//5.3
func visitText(texts []string, n *html.Node) []string {
	if n == nil || n.Data == "script" || n.Data == "style" {
		return texts 
	}
	if n.Type == html.TextNode {
		texts = append(texts, n.Data)
	}
	texts = visitText(texts, n.FirstChild)
	texts = visitText(texts, n.NextSibling)
	return texts
}

// 5.4 
var visitData = map[string]int{
	"a": 1,
	"img": 1,
	"link": 1,
	"script": 1,
}
func visitExtend(links []string, n *html.Node) []string {
	if n == nil {
		return links 
	}
	
	if n.Type == html.ElementNode {
		if _, v := visitData[n.Data]; v {
			for _, a := range n.Attr {
				if a.Key == "href" {
					links = append(links, a.Val)
				}
			}
		}
	}

	links = visitExtend(links, n.FirstChild)
	links = visitExtend(links, n.NextSibling)
	return links
}

測試

https://golang.org/ 上不去,改用go語言中文網代替

go build gopl.io/ch1/fetch
go build gopl.io/ch5/findlinks1
fetch https://studygolang.com/ | findlinks1

前面幾條展示如下。(經過對比,原來的寫法結果與修改遞歸的結果一致)

/
/topics
/articles
/projects
/resources
/books
/go/weekly
https://course.studygolang.com
/dl
#
http://docs.studygolang.com
http://docscn.studygolang.com

參考:
https://github.com/ivanbeldad/the-go-programming-language/blob/master/ch05/ex02/main.go

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章