GO语言圣经 第五章习题
练习5.1
修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。
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)}}}links = visit(links, n.NextSibling)links = visit(links, n.FirstChild)return links
}
练习5.2
编写函数,记录在HTML树中出现的同名元素的次数。
package mainimport ("fmt""os""golang.org/x/net/html"
)type NodeCount map[string]intfunc main() {doc, err := html.Parse(os.Stdin)if err != nil {fmt.Fprintf(os.Stderr, "findlinks1: %v\n", err)os.Exit(1)}nodeCount := NodeCount{}fill(&nodeCount, doc)fmt.Printf("%v", nodeCount)
}func fill(nc *NodeCount, cn *html.Node) {if cn.Type == html.ElementNode {(*nc)[cn.Data]++}for next := cn.FirstChild; next != nil; next = next.NextSibling {fill(nc, next)}
}
练习5.3
编写函数输出所有text结点的内容。注意不要访问<script>和<style>元素,因为这些元素对浏览者是不可见的。
func getText(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 = getText(texts, c)}return texts
}
练习5.4
扩展visit函数,使其能够处理其他类型的结点,如images、scripts和style sheets。
func visit(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" {// fmt.Println(n.Data)links = append(links, a.Val)}}}for c := n.FirstChild; c != nil; c = c.NextSibling {links = visit(links, c)}return links
}
练习5.5
实现countWordsAndImages。(参考练习4.9如何分词)
func countWordsAndImages(n *html.Node) (words, images int) {texts, images := visit(nil, 0, n)for _, v := range texts {words += len(strings.Split(v, " "))v = strings.Trim(strings.TrimSpace(v), "\r\n")if v == "" {continue}words += len(strings.Split(v, " "))}return
}func visit(texts []string, imgs int, n *html.Node) ([]string, int) {if n.Type == html.TextNode {texts = append(texts, n.Data)}if n.Type == html.ElementNode && (n.Data == "img") {imgs++}for c := n.FirstChild; c != nil; c = c.NextSibling {if c.Data == "script" || c.Data == "style" {continue}texts, imgs = visit(texts, imgs, c)}return texts, imgs
}
练习5.6
修改gopl.io/ch3/surface(§3.2)中的corner函数,将返回值命名,并使用bare return。
func corner(i, j int) (sx float64, sy float64) {// Find point (x,y) at corner of cell (i,j).x := xyrange * (float64(i)/cells - 0.5)y := xyrange * (float64(j)/cells - 0.5)// Compute surface height z.z := f(x, y)// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).sx := width/2 + (x-y)*cos30*xyscalesy := height/2 + (x+y)*sin30*xyscale - z*zscalereturn
}
练习5.7
完善startElement和endElement函数,使其成为通用的HTML输出器。要求:输出注释结点,文本结点以及每个元素的属性(< a href=‘…’>)。使用简略格式输出没有孩子结点的元素(即用<img/>代替<img></img>)。编写测试,验证程序输出的格式正确。(详见11章)
func startElement(n *html.Node) {if n.Type == html.ElementNode {attr := ""for _, a := range n.Attr {attr += " " + a.Key + "=" + "\"" + a.Val + "\" "}fmt.Printf("%*s<%s%s", depth*2, "", n.Data, attr)depth++}if n.Type == html.ElementNode && n.FirstChild == nil && n.Data != "script" {fmt.Printf("/>\n")} else if n.Type == html.ElementNode {fmt.Printf(">\n")}if n.Type == html.TextNode {fmt.Printf("%*s %s\n", depth*2, "", n.Data)}
}
func endElement(n *html.Node) {if n.Type == html.ElementNode && n.FirstChild == nil && n.Data != "script" {depth--fmt.Printf("\n")return}if n.Type == html.ElementNode {depth--fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)}
}
练习5.8
修改pre和post函数,使其返回布尔类型的返回值。返回false时,中止forEachNoded的遍历。使用修改后的代码编写ElementByID函数,根据用户输入的id查找第一个拥有该id元素的HTML元素,查找成功后,停止遍历。
func ElementByID(n *html.Node, id string) *html.Node {if n.Type == html.ElementNode {for _, a := range n.Attr {if a.Key == "id" && a.Val == id {return n}}}for c := n.FirstChild; c != nil; c = c.NextSibling {ElementByID(c, id)}return n
}
练习5.9
编写函数expand,将s中的"foo"替换为f(“foo”)的返回值。
func expand(s string, f func(string) string) string {str := f("foo")s = strings.Replace(s, "foo", str, -1)return s
}
func f(s string) string {return s + "_expand_"
}
练习5.10
重写topoSort函数,用map代替切片并移除对key的排序代码。验证结果的正确性(结果不唯一)。
func topoSort2(m map[string][]string) map[int]string {var order = make(map[int]string)index := 1seen := make(map[string]bool)var visitAll func(items []string)visitAll = func(items []string) {for _, item := range items {if !seen[item] {seen[item] = truevisitAll(m[item])order[index] = itemindex++}}}var keys []stringfor key := range m {keys = append(keys, key)}visitAll(keys)return order
}
练习5.11
博客
练习5.12
gopl.io/ch5/outline2(5.5节)的startElement和endElement共用了全局变量depth,将它们修改为匿名函数,使其共享outline中的局部变量。
func outline(url string) (string, error) {resp, err := http.Get(url)if err != nil {return "", err}doc, _ := html.Parse(resp.Body)//使用匿名函数实现var depth intvar startElement func(n *html.Node)var endElement func(n *html.Node)startElement = func (n *html.Node) {if n.Type == html.ElementNode {fmt.Printf("%*s<%s>\n", depth*2, "", n.Data)depth++}}endElement = func (n *html.Node) {if n.Type == html.ElementNode {depth--fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)}}forEachNode(doc, startElement, endElement)resp.Body.Close()return "", nil
}
练习5.15
编写类似sum的可变参数函数max和min。考虑不传参时,max和min该如何处理,再编写至少接收1个参数的版本。
func max(vals ...int) (int, error) {var m int = math.NaN()if len(vals) == 0 { return m, fmt.Errorf("max: %s", "至少传递一个参数")} for _, v := range vals {if m < v { m = v } } return m, nil
}
练习5.16
编写多参数版本的strings.Join。
func join(sep string, strs ...string) string {var res stringfor i, v := range strs {if i == (len(strs) - 1) {res += v} else {res += v + sep}}return res
}
练习5.17
编写多参数版本的ElementsByTagName,函数接收一个HTML结点树以及任意数量的标签名,返回与这些标签名匹配的所有元素。
var nodes []*html.Node
func ElementsByTagName(n *html.Node, names ...string) []*html.Node {for _, name := range names {if n.Type == html.ElementNode && n.Data == name {nodes = append(nodes, n)}}for c := n.FirstChild; c != nil; c = c.NextSibling {ElementsByTagName(c, names...)}return nodes
}
练习5.18
不修改fetch的行为,重写fetch函数,要求使用defer机制关闭文件。
参考博客
func fetch(url string) (filename string, n int64, err error) {resp, err := http.Get(url)if err != nil {return "", 0, err}defer resp.Body.Close()local := path.Base(resp.Request.URL.Path)if local == "/" {local = "index.html"}f, err := os.Create(local)if err != nil {return "", 0, err}defer func() {closeErr := f.close()if err == nil {err = closeErr}}()n, err = io.Copy(f, resp.Body)return local, n, err
}
相关文章:
GO语言圣经 第五章习题
练习5.1 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。 func visit(links []string, n *html.Node) []string {if n nil {return links}if n.Type html.ElementNode && n.Data "a" {for _, a : r…...
用kotlin 开发一个简单的多页面跳转
本文介绍一个简单的安卓应用的页面跳转例子,用的是kotlin。 运行时主页面是一个hello 和Jump 按钮,你按一下jump 按钮就转到 从页面,只是标识从页面。 开始建立一个简单工程,名为hello, 选择的是Empty views Activit…...
记录我的tensorrt 部署yolov8
系统 :ubuntu 18.04 代码 :GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT conda 环境 : GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT cuda : 11.8 …...
什么是用户界面? 优漫动游
什么是用户界面? 用户界面(UI,UserInterface)也称人机界面,是人机交互、操作逻辑和界面表现的整体设计。每一种设计都有其对应的职业角色,其中,人机交互的设计人员叫做用户研究工程师,操作逻辑设计人员叫…...
基于 Docker 的 MySQL 主从复制搭建(Mac M1版本)
系统:Macbook M1 镜像版本:mysql:5.7 如果是要查 slave连接不上 master的问题,可以直接跳到文章末尾踩坑处 准备工作 拉取镜像 docker pull mysql:5.7本地数据卷挂载 因为mysql不挂载的话,重启丢失数据,所以在本地创…...
【Locomotor运动模块】瞬移
文章目录 一、原理二、两种类型1、Instant(立刻)2、Dash(猛冲) 三、瞬移区域、瞬移点1、瞬移区域2、瞬移点 一、原理 抛物线指针选择好目标位置,然后告诉瞬移预设体:你想法把游戏区域弄到目标位置来 解释:抛物线指针选…...
【负载均衡】常见的负载均衡策略有哪些?
文章目录 前言负载均衡分类常见负载均衡策略小结 前言 负载均衡策略是实现负载均衡器的关键,而负载均衡器又是分布式系统中不可或缺的重要组件。使用它有助于提高系统的整体性能、可用性、可靠性和安全性,同时支持系统的扩展和故障容忍性。对于处理大量…...
ChatGPT如何应对紧急救援和医疗应急?
ChatGPT在紧急救援和医疗应急方面具有潜在的重要用途。它可以用于提供信息、建议和支持,以帮助应对各种突发事件,如自然灾害、流行病爆发、事故等。以下是ChatGPT如何应对紧急救援和医疗应急的方式以及相关挑战的详细讨论。 ### 紧急救援 #### 1. 提供…...
vue3 ref reactive响应式数据 赋值的问题
文章目录 vue3 ref reactive响应式数据 赋值的问题场景1:将响应式数据赋值请求后的数据错误示范:直接赋值正确写法 场景2:响应式数据解构之后失去响应式原因分析解决办法 toRefs/toRef方法创建ref引用对象 vue3 ref reactive响应式数据 赋值的问题 doing…...
【美团秋招】20230922小美的彩虹糖
小美的彩虹糖 小美有很多的彩虹糖,每颗彩虹糖都有一个颜色,她每天可以吃两颗彩虹糖,如果今天吃的彩虹糖组合是之前没吃过的组合,则小美今天会很高兴。 例如,小美有 6 颗彩虹糖,颜色分别是 [1,1,4,5,1,4]。…...
论文阅读_扩散模型_DM
英文名称: Deep Unsupervised Learning using Nonequilibrium Thermodynamics 中文名称: 使用非平衡热力学原理的深度无监督学习 论文地址: http://arxiv.org/abs/1503.03585 代码地址: https://github.com/Sohl-Dickstein/Diffusion-Probabilistic-Models 时间: 2015-11-18 作…...
【每日运维】RockyLinux8.6升级OpenSSH9.4p1
为什么需要升级openssh呢,因为很多项目进行漏扫结果都会涉及到这个服务器核心组件,一想到以前升级openssh带来的各种依赖性问题就头疼,不管是什么发行版,升级这个东西真的很烦,这次发现可能还会有好一点的通用一点的升…...
libdrm全解析三十八 —— 源码全解析(35)
接前一篇文章:libdrm全解析三十七 —— 源码全解析(34) 本文参考以下博文: DRM 驱动程序开发(VKMS) 特此致谢! 前一篇文章讲解完了drmModeSetCrtc(crtc_id, fb_id, connector_id, mode)&#…...
jar包和war包的区别
SpringBoot项目既可以打成war包发布,也可以找成jar包发布。 jar包 jar包:直接通过内置Tomcat运行,不需要额外安装Tomcat。如需修改内置Tomcat的配置,只需要在SpringBoot的配置文件中配置。内置Tomcat没有自己的日志输出࿰…...
CloudCompare 二次开发(10)——点云投影到平面
目录 一、概述二、代码集成三、结果展示一、概述 不依赖任何第三方点云相关库,使用CloudCompare编程实现点云投影到指定平面,具体计算原理见:PCL 点云投影到拟合平面 二、代码集成 1、mainwindow.h文件public中添加: void doActionProjectToPlane(); // 投影到平面2、…...
如何制作并运行 jar 程序
以下是用 Intellij 制作 jar 程序,并运行的方法。 【1】新建工程,保持默认选项,Next 【2】保持默认选项,Next 【3】给工程命名,设置保存位置,Finish 【4】新建工程结束,进入开发界面 【5】展开…...
Hadoop MapReduce 调优参数
文章目录 MapReduce 调优参数详解MapReduce 调优参数一键复制 前言: 下列参数基于 hadoop v3.1.3 版本,共三台服务器,配置都为 4 核,4G 内存。 MapReduce 调优参数详解 这个参数定义了在 Reduce 阶段同时进行的拷贝操作的数量&…...
springboot 与 Redis整合
SpringBoot 操作数据:Spring-data jpa jdbc mongodb redis! SpringData 也是和SpringBoot 齐名的项目! 说明:在SpringBoot2.X 之后,原来使用的jedis被替换成了lettuce jedis: 采用的直连,多个线程操作的话&…...
如何高效地设计测试用例并评审
编写出好的测试用例是每一个测试工程师的职责,但在实际工作中大家写的测试用例往往需要不断地修改才能使用,这不仅浪费了时间,还容易让测试工程师产生自我否定的情绪,甚至在团队中产生各种矛盾。 那如何高效地设计测试用例呢&…...
基于python+Django知识图谱的医疗问答系统设计与实现
摘 要 从信息技术的发展至今,各色各样的技术能够满足各类人群的需求,能够让各种业务行业的痛点变成能够可以解决的方法,随着我们经济的不断提高,越来越多的人都该关注健康,那么健康饮食、健康医疗是我们生活中所追求的…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
