练习 5.1: 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。

练习 5.2: 编写函数,记录在HTML树中出现的同名元素的次数。

练习 5.3: 编写函数输出所有text结点的内容。注意不要访问<script>和<style>元素,因为这些元素对浏览者是不可见的。

练习 5.4: 扩展visit函数,使其能够处理其他类型的结点,如images、scripts和style sheets。

// Findlinks1 prints the links in an HTML document read from standard input.
package main import (
"fmt"
"os" "golang.org/x/net/html"
) 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)
} var res = make(map[string]int)
res = count(res, doc)
for k, v := range res {
fmt.Printf("%s==>%d \n", k, v)
}
//fmt.Println(res)
for _, text := range visit3(nil, doc) {
fmt.Println(text)
} for _, link := range visit4(nil, doc) {
fmt.Println(link)
} } // visit appends to links each link found in n and returns the result.
func visit(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
/*
练习 5.1: 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。
实在是不知道为啥不对,我选择放弃
if n.FirstChild!=nil{
links=visit(links,n.FirstChild)
}else if n.NextSibling!=nil{
//n=n.NextSibling
links=visit(links,n.NextSibling)
}
*/
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
return links
} /*
练习 5.2: 编写函数,记录在HTML树中出现的同名元素的次数。
*/
func count(res map[string]int, n *html.Node) map[string]int {
if n.Type == html.ElementNode {
res[n.Data]++
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
res = count(res, c)
}
return res
} /*
练习 5.3: 编写函数输出所有text结点的内容。注意不要访问<script>和<style>元素,因为这些元素对浏览者是不可见的。
*/
func visit3(texts []string, n *html.Node) []string {
if n.Type == html.TextNode {
texts = append(texts, n.Data)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
if c.Data == "script" || c.Data == "style" {
continue
} texts = visit3(texts, c)
}
return texts
} /*
练习 5.4: 扩展visit函数,使其能够处理其他类型的结点,如images、scripts和style sheets。
*/
func visit4(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && (n.Data == "a" || n.Data == "img" || n.Data == "link" || n.Data == "scripts") {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit4(links, c)
}
return links
}

  

[日常] Go语言圣经-函数递归习题的更多相关文章

  1. [日常] Go语言圣经-函数多返回值习题

    Go语言圣经-函数多返回值1.在Go中,一个函数可以返回多个值2.许多标准库中的函数返回2个值,一个是期望得到的返回值,另一个是函数出错时的错误信息3.如果一个函数将所有的返回值都显示的变量名,那么该 ...

  2. [日常] Go语言圣经-错误,函数值习题

    Go语言圣经-错误 1.panic异常.panic是来自被调函数的信号,表示发生了某个已知的bug 2.任何进行I/O操作的函数都会面临出现错误的可能 3.错误是软件包API和应用程序用户界面的一个重 ...

  3. [日常] Go语言圣经--接口约定习题

    Go语言圣经-接口1.接口类型是对其它类型行为的抽象和概括2.Go语言中接口类型的独特之处在于它是满足隐式实现的3.Go语言中还存在着另外一种类型:接口类型.接口类型是一种抽象的类型4.一个类型可以自 ...

  4. [日常] Go语言圣经-竞争条件习题

    package main import( "fmt" "sync" ) var balance int func Deposit(amount int) { b ...

  5. [日常] Go语言圣经-可变参数习题

    1.参数数量可变的函数称为为可变参数函数,例子就是fmt.Printf和类似函数2.参数列表的最后一个参数类型之前加上省略符号“...”3.虽然在可变参数函数内部,...int 型参数的行为看起来很像 ...

  6. [日常] Go语言圣经-Slice切片习题

    1.Slice(切片)代表变长的序列,序列中每个元素都有相同的类型,一个slice类型一般写作[]T,其中T代表slice中元素的类型:slice的语法和数组很像,只是没有固定长度而已,slice的底 ...

  7. [日常] Go语言圣经--接口约定习题2

    练习 7.3: 为在gopl.io/ch4/treesort (§4.4)的*tree类型实现一个String方法去展示tree类型的值序列. package main import( "f ...

  8. [日常] Go语言圣经-匿名函数习题

    Go语言圣经-匿名函数1.拥有函数名的函数只能在包级语法块中被声明,通过函数字面量(function literal),我们可绕过这一限制,在任何表达式中表示一个函数值2.通过这种方式定义的函数可以访 ...

  9. [日常] Go语言圣经--复数,布尔值,字符串习题

    go语言圣经-复数 1.我们把形如a+bi(a,b均为实数)的数称为复数,其中a称为实部,b称为虚部,i称为虚数单位.两种精度的复数类型:complex64和complex128,分别对应float3 ...

随机推荐

  1. ASP.NET Web API 中使用 swagger 来管理 API 文档

    本文以 ASP.NET Web API 为后台框架,利用 EF6 连接 postgreSQL 数据库,使用 swagger 来生成 REST APIs文档.文章分二个部分,第一部分主要讲如何用 EF6 ...

  2. ASP.NET MVC高亮显示当前页面菜单

    1.创建MvcHtmlExtension扩展类 public static class MvcHtmlExtension { public static MvcHtmlString MenuLink( ...

  3. SoftWareHelper

    SoftWareHelper 环境 Visual Studio 2017,.Net Framework 4.0 SDK GitHub源码:https://github.com/yanjinhuagoo ...

  4. 【转】AngularJs HTTP请求响应拦截器

    任何时候,如果我们想要为请求添加全局功能,例如身份认证.错误处理等,在请求发送给服务器之前或服务器返回时对其进行拦截,是比较好的实现手段. angularJs通过拦截器提供了一个从全局层面进行处理的途 ...

  5. 【五校联考3day2】C

    題意: 現有一平面直角坐標系,有n個點,每一個點必須向某一個方向發射射線,且任意一條射線必須與某一條坐標軸平行.定義一種發射射線的方案是合法的,則方案必須滿足: 1.沒有一條射線交叉 2.沒有一條射線 ...

  6. PHP进行数据库操作时遇到的一个问题

    PHP进行数据库操作时遇到的一个问题 昨天在进行数据库操作时,遇到了一个问题(用的是 wampserver 环境): <?php $link = @mysqli_connect('localho ...

  7. raspberry pi wifi

    vim /etc/network/interfaces 修改 wpa-ssid 和 wpa-psk

  8. 协程 coroutine

    参考链接: http://manual.luaer.cn/2.11.html http://www.cnblogs.com/riceball/archive/2008/01/03/1025158.ht ...

  9. 读配置文件property文件

    import java.io.IOException;import java.util.Properties; import org.springframework.core.io.support.P ...

  10. Vue.js之下拉列表及选中触发事件

    老早就听说了Vue.js是多么的简单.易学.好用等等,然而我只是粗略的看了下文档,简单的敲了几个例子,仅此而已. 最近由于项目的需要,系统的看了下文档,也学到了一些东西. 废话不多说,这里要说的是下拉 ...