Golang中x/net/html的Token.Data与标准字符串无法比较的问题
Golang中x/net/html的Token.Data与标准字符串无法比较的问题 最近我在处理一些需要搜索HTML内容的工作时,遇到了一个奇怪的问题。我是从其他语言转到Go的新手,所以如果我遗漏了什么细节,请见谅。
x/net/html.Token的Data结构成员是一个字符串,但我无法对它进行任何类型的字符串比较?
最小可工作示例:
package main
import (
"fmt"
"io"
"log"
"reflect"
"strings"
"golang.org/x/net/html"
)
func main() {
dat := `<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><apm_do_not_touch><body onload="document.forms[0].submit()"><noscript> <p> <strong> Your browser does not support JavaScript, press the Continue button once to proceed. </strong></p> </noscript> <form action="https://website.com" method="post"> <input type="hidden" name="SomeName" value="SomeValue"/><noscript> <div> <input type="submit" value="DoStuff"/></div> </noscript> </form></body></apm_do_not_touch></html>`
reader := strings.NewReader(dat)
tokenizer := html.NewTokenizer(reader)
//主要来自 https://drstearns.github.io/tutorials/tokenizing/
for {
//获取下一个令牌类型
tokenType := tokenizer.Next()
//如果是错误令牌,我们要么到达了
//文件末尾,要么HTML格式错误
if tokenType == html.ErrorToken {
err := tokenizer.Err()
if err == io.EOF {
//文件结束,跳出循环
break
}
//否则,令牌化过程中出现错误,
//这可能意味着HTML格式错误。
//由于这是一个简单的命令行工具,
//我们可以直接使用log.Fatalf()来报告错误
//并以非零状态码退出进程
log.Fatalf("error tokenizing HTML: %v", tokenizer.Err())
}
//根据令牌类型处理令牌...
//input是一个自闭合令牌
if tokenType == html.SelfClosingTagToken {
fmt.Println(tokenizer.Token().Data)
fmt.Println("input")
data := tokenizer.Token().Data
//这些似乎匹配
fmt.Println("t1:", reflect.TypeOf(tokenizer.Token().Data))
fmt.Println("t2:", reflect.TypeOf("input"))
//这些似乎匹配
fmt.Println("len1:", len(tokenizer.Token().Data))
fmt.Println("len2:", len("input"))
fmt.Println("len3:", len(data))
fmt.Println("compare1:", "input" == tokenizer.Token().Data)
fmt.Println("compare2:", strings.Compare(tokenizer.Token().Data, "input") == 0)
fmt.Println("compare3:", "" == tokenizer.Token().Data)
fmt.Println("compare4:", strings.Compare(tokenizer.Token().Data, "") == 0)
fmt.Println("compare5:", "input" == data)
fmt.Println("compare6:", strings.Compare(data, "input") == 0)
if tokenizer.Token().Data == "input" {
fmt.Println("我们从未到达这里")
}
}
}
}
根据文档,Data应该是一个字符串(reflect.TypeOf语句似乎也显示了这一点),但它不显示任何长度,而且我无法检查与它的相等性?有人知道这是怎么回事吗?我假设如果文档有误,而我实际上得到的是一个指针或引用之类的,它应该会在TypeOf检查中显示出来,但所有结果都只显示string。
更多关于Golang中x/net/html的Token.Data与标准字符串无法比较的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你只能在每个循环中调用一次 Token()。第一次调用 tokenizer.Token().Data 返回 "input",但第二次调用 tokenizer.Token() 返回一个数据为空的 Token,因此所有后续检查都会失败。你应该改用 data 变量,而不是持续调用 tokenizer.Token()。
func main() {
fmt.Println("hello world")
}
更多关于Golang中x/net/html的Token.Data与标准字符串无法比较的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
好的,我现在明白了。
以下是修正后的完整代码块:
if tokenType == html.SelfClosingTagToken {
data := tokenizer.Token().Data
//fmt.Println(tokenizer.Token().Data)
fmt.Println("input")
fmt.Println(data)
fmt.Println("len2:", len("input"))
fmt.Println("len3:", len(data))
fmt.Println("compare5:", "input" == data)
fmt.Println("compare6:", strings.Compare(data, "input") == 0)
if data == "input" {
fmt.Println("Now we reach this!")
}
输出:
input
input
len2: 5
len3: 5
compare5: true
compare6: true
Now we reach this!
在Go语言中,x/net/html包的Token.Data字段确实是string类型。你遇到的问题很可能是由于HTML解析器返回的令牌数据包含了额外的空白字符或不可见字符,导致字符串比较失败。
以下是修正后的代码示例,展示了如何正确处理这种情况:
package main
import (
"fmt"
"io"
"log"
"strings"
"unicode"
"golang.org/x/net/html"
)
func main() {
dat := `<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><apm_do_not_touch><body onload="document.forms[0].submit()"><noscript> <p> <strong> Your browser does not support JavaScript, press the Continue button once to proceed. </strong></p> </noscript> <form action="https://website.com" method="post"> <input type="hidden" name="SomeName" value="SomeValue"/><noscript> <div> <input type="submit" value="DoStuff"/></div> </noscript> </form></body></apm_do_not_touch></html>`
reader := strings.NewReader(dat)
tokenizer := html.NewTokenizer(reader)
for {
tokenType := tokenizer.Next()
if tokenType == html.ErrorToken {
err := tokenizer.Err()
if err == io.EOF {
break
}
log.Fatalf("error tokenizing HTML: %v", tokenizer.Err())
}
if tokenType == html.SelfClosingTagToken {
token := tokenizer.Token()
data := token.Data
// 方法1: 使用strings.TrimSpace去除空白字符
trimmedData := strings.TrimSpace(data)
fmt.Printf("原始数据: '%s' (长度: %d)\n", data, len(data))
fmt.Printf("修剪后: '%s' (长度: %d)\n", trimmedData, len(trimmedData))
// 方法2: 使用strings.TrimFunc去除空白字符
cleanedData := strings.TrimFunc(data, func(r rune) bool {
return unicode.IsSpace(r)
})
// 方法3: 直接比较(如果确定没有空白字符)
if trimmedData == "input" {
fmt.Println("找到input标签 (使用TrimSpace)")
}
if cleanedData == "input" {
fmt.Println("找到input标签 (使用TrimFunc)")
}
// 方法4: 使用strings.EqualFold进行不区分大小写的比较
if strings.EqualFold(trimmedData, "input") {
fmt.Println("找到input标签 (不区分大小写)")
}
// 调试输出:显示每个字符的ASCII码
fmt.Print("字符编码: ")
for _, ch := range data {
fmt.Printf("%d ", ch)
}
fmt.Println()
}
}
}
关键点说明:
-
空白字符问题:HTML解析器可能返回包含换行符、制表符或其他空白字符的字符串。使用
strings.TrimSpace()可以去除这些字符。 -
字符编码检查:通过遍历字符串并打印每个字符的ASCII码,可以查看是否有不可见字符。
-
字符串比较方法:
strings.TrimSpace():去除首尾空白字符strings.TrimFunc():自定义去除函数strings.EqualFold():不区分大小写的比较
-
调试技巧:打印字符串长度和原始字符编码有助于识别问题。
运行这个修改后的代码,你会看到Token.Data确实包含字符串"input",但可能带有额外的空白字符。使用适当的字符串清理方法后,比较操作就能正常工作了。

