练习 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. Flash插件flashplugin-nonfree的手动更新

    Debian,nonfree库里有flashplugin-nonfree,这个就是网页浏览器的Flash插件了.不过它好像不会自动更新,每次更新网页浏览器后都会提示flashplugin版本过低.但f ...

  2. C# 动态创建SQL数据库(一)

    最近在做项目中要求能够要求动态添加数据库并建表.具体思路如下 1 提供数据名,根据数据库创建数据库 2 自定数据库与数据表,提供数据表自定与数据类型创建表 创建sqlhelper类,用于数据库操作 u ...

  3. OSLab文件描述符

      日期:2019/3/24 内容:Linux文件描述符.   一.基本概念 文件描述符(File Descriptor) 一个非负整数.应用程序利用文件描述符来访问文件.打开现存文件或新建文件时,内 ...

  4. 12_python_生成器

    一.生成器 python中有三种方式获取生成器 (1)通过生成器函数 (2)通过各种推导式来实现生成器 (3)通过数据的转换也可以获取生成器   1.只要函数中存在了yield,那么这个函数就是一个生 ...

  5. Weblogic 错误 <BEA-000403> <BEA-000438>解决办法

      控制台提示如下错误: <Error> <Socket> <BEA-000438> <Unable to load performance pack. Us ...

  6. Java - 初识Java

    Java是一种跨平台的面向对象的程序设计语言. 区分大小写: 标点符号为英文: 强类型语言,在Java中存储的数据,必须在编译时确定其类型: Java版本 Java按应用范围分为3个版本,即Java ...

  7. Others - On Duty

    On Duty This is xxx and will be duty engineer in the next week. Thanks. Here is a kindly reminder. T ...

  8. [Leetcode]44.跳跃游戏Ⅰ&&45.跳跃游戏Ⅱ

    跳跃游戏链接 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4] 输出 ...

  9. Strom的trident小例子

    上代码: public class TridentFunc { /** * 类似于普通的bolt */ public static class MyFunction extends BaseFunct ...

  10. Installation failed with message...It is possible that this issue is resolved by uninstalling an existing version of the apk if it is present, and then re-installing.

    错误弹窗如图: Installation failed with message Failed to finalize session: INSTALL_FAILED_TEST_ONLY:instal ...