package scanner
import "text/scanner"
Package scanner 提供 UTF-8 编码文本的扫描器和分词器。 它接受一个 io.Reader 作为输入源,然后可以通过反复调用 Scan 函数对其进行分词。 为了与现有工具兼容,不允许使用 NUL 字符。如果源代码的第一个字符是 UTF-8 编码的 字节顺序标记(BOM),它将被丢弃。
默认情况下,Scanner 会跳过空白字符和 Go 注释,并识别 Go 语言规范中定义的所有字面量。
可以对其进行自定义,以仅识别这些字面量的子集,以及识别不同的标识符和空白字符。
Output: Output: Output: Output:Example
package main
import (
"fmt"
"strings"
"text/scanner"
)
func main() {
const src = `
// This is scanned code.
if a > 10 {
someParsable = text
}`
var s scanner.Scanner
s.Init(strings.NewReader(src))
s.Filename = "example"
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
fmt.Printf("%s: %s\n", s.Position, s.TokenText())
}
}
example:3:1: if
example:3:4: a
example:3:6: >
example:3:8: 10
example:3:11: {
example:4:2: someParsable
example:4:15: =
example:4:17: text
example:5:1: }
Example (IsIdentRune)
package main
import (
"fmt"
"strings"
"text/scanner"
"unicode"
)
func main() {
const src = "%var1 var2%"
var s scanner.Scanner
s.Init(strings.NewReader(src))
s.Filename = "default"
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
fmt.Printf("%s: %s\n", s.Position, s.TokenText())
}
fmt.Println()
s.Init(strings.NewReader(src))
s.Filename = "percent"
// treat leading '%' as part of an identifier
s.IsIdentRune = func(ch rune, i int) bool {
return ch == '%' && i == 0 || unicode.IsLetter(ch) || unicode.IsDigit(ch) && i > 0
}
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
fmt.Printf("%s: %s\n", s.Position, s.TokenText())
}
}
default:1:1: %
default:1:2: var1
default:1:7: var2
default:1:11: %
percent:1:1: %var1
percent:1:7: var2
percent:1:11: %
Example (Mode)
package main
import (
"fmt"
"strings"
"text/scanner"
)
func main() {
const src = `
// Comment begins at column 5.
This line should not be included in the output.
/*
This multiline comment
should be extracted in
its entirety.
*/
`
var s scanner.Scanner
s.Init(strings.NewReader(src))
s.Filename = "comments"
s.Mode ^= scanner.SkipComments // don't skip comments
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
if strings.HasPrefix(txt, "//") || strings.HasPrefix(txt, "/*") {
fmt.Printf("%s: %s\n", s.Position, txt)
}
}
}
comments:2:5: // Comment begins at column 5.
comments:6:1: /*
This multiline comment
should be extracted in
its entirety.
*/
Example (Whitespace)
package main
import (
"fmt"
"strings"
"text/scanner"
)
func main() {
// tab-separated values
const src = `aa ab ac ad
ba bb bc bd
ca cb cc cd
da db dc dd`
var (
col, row int
s scanner.Scanner
tsv [4][4]string // large enough for example above
)
s.Init(strings.NewReader(src))
s.Whitespace ^= 1<<'\t' | 1<<'\n' // don't skip tabs and new lines
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
switch tok {
case '\n':
row++
col = 0
case '\t':
col++
default:
tsv[row][col] = s.TokenText()
}
}
fmt.Print(tsv)
}
[[aa ab ac ad] [ba bb bc bd] [ca cb cc cd] [da db dc dd]]
Index
Examples
Constants
const ( ScanIdents = 1 << -Ident ScanInts = 1 << -Int ScanFloats = 1 << -Float // includes Ints and hexadecimal floats ScanChars = 1 << -Char ScanStrings = 1 << -String ScanRawStrings = 1 << -RawString ScanComments = 1 << -Comment SkipComments = 1 << -skipComment // if set with ScanComments, comments become white space GoTokens = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments )
预定义模式位,用于控制词法记号的识别。例如,要配置 Scanner 仅识别 Go 标识符、 整数并跳过注释,请将 Scanner 的 Mode 字段设置为:
ScanIdents | ScanInts | ScanComments | SkipComments
除了注释(在设置 SkipComments 时会被跳过)之外,未识别的词法记号不会被忽略。 相反,扫描器会简单地返回各个单独的字符(或者可能是子记号)。例如,如果模式为 ScanIdents(非 ScanStrings),则字符串 "foo" 会被扫描为词法记号序列 '"' Ident '"'。
使用 GoTokens 配置 Scanner,使其接受所有 Go 字面量词法记号,包括 Go 标识符。 注释将被跳过。
const ( EOF = -(iota + 1) Ident Int Float Char String RawString Comment )
Scan 的结果是以下词法记号之一或一个 Unicode 字符。
const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
GoWhitespace 是 Scanner 的 Whitespace 字段的默认值。 它的值选择 Go 的空白字符。
Functions
func TokenString
func TokenString(tok rune) string
TokenString 返回词法记号或 Unicode 字符的可打印字符串。
Types
type Position
type Position struct { Filename string // filename, if any Offset int // byte offset, starting at 0 Line int // line number, starting at 1 Column int // column number, starting at 1 (character count per line) }
Position 表示源代码位置的值。 当 Line > 0 时,位置有效。
func (*Position) IsValid
func (pos *Position) IsValid() bool
IsValid 报告位置是否有效。
func (Position) String
func (pos Position) String() string
type Scanner
type Scanner struct { // Error 在遇到每个错误时被调用。如果没有设置 Error 函数, // 则错误会被报告到 os.Stderr。 Error func(s *Scanner, msg string) // ErrorCount 在遇到每个错误时递增一。 ErrorCount int // Mode 字段控制识别哪些词法记号。例如,要识别整数, // 请在 Mode 中设置 ScanInts 位。该字段可随时更改。 Mode uint // Whitespace 字段控制哪些字符被识别为空白字符。要将字符 ch <= ' ' 识别为空白字符, // 请在 Whitespace 中设置第 ch 位(Scanner 对于 ch > ' ' 的值的行为是未定义的)。 // 该字段可随时更改。 Whitespace uint64 // IsIdentRune 是一个谓词,控制哪些字符被接受为标识符中第 i 个字符。 // 有效字符集不得与空白字符集相交。如果未设置 IsIdentRune 函数, // 则会接受常规的 Go 标识符。该字段可随时更改。 IsIdentRune func(ch rune, i int) bool // 最近扫描的词法记号的起始位置;由 Scan 设置。 // 调用 Init 或 Next 会使该位置失效(Line == 0)。 // Scanner 始终不会修改 Filename 字段。 // 如果报告了错误(通过 Error)且 Position 无效,则扫描器不在词法记号内。 // 在这种情况下,调用 Pos 获取错误位置,或者获取最近扫描的词法记号之后的位置。 Position // contains filtered or unexported fields }
Scanner 实现了从 io.Reader 读取 Unicode 字符和词法记号。
func (*Scanner) Init
func (s *Scanner) Init(src io.Reader) *Scanner
Init 使用新的源初始化 Scanner 并返回 s。 Scanner.Error 被设置为 nil,Scanner.ErrorCount 被设置为 0, Scanner.Mode 被设置为 GoTokens,Scanner.Whitespace 被设置为 GoWhitespace。
func (*Scanner) Next
func (s *Scanner) Next() rune
Next 读取并返回下一个 Unicode 字符。 在源结束时返回 EOF。如果 s.Error 不为 nil,它会通过调用 s.Error 报告读取错误; 否则打印错误消息到 os.Stderr。Next 不更新 [Scanner.Position] 字段; 使用 Scanner.Pos() 获取当前位置。
func (*Scanner) Peek
func (s *Scanner) Peek() rune
Peek 返回源中的下一个 Unicode 字符,但不推进扫描器。 如果扫描器位置在源的最后一个字符处,则返回 EOF。
func (*Scanner) Pos
func (s *Scanner) Pos() (pos Position)
Pos 返回上一次调用 Scanner.Next 或 Scanner.Scan 所返回的字符或词法记号 之后那个字符的位置。使用 [Scanner.Position] 字段获取最近扫描的词法记号的起始位置。
func (*Scanner) Scan
func (s *Scanner) Scan() rune
Scan 从源中读取下一个词法记号或 Unicode 字符并返回它。 它只识别设置了相应 Scanner.Mode 位 (1<<-t) 的词法记号 t。 在源结束时返回 EOF。如果 s.Error 不为 nil,它通过调用 s.Error 报告 扫描器错误(读取错误和词法记号错误);否则打印错误消息到 os.Stderr。
func (*Scanner) TokenText
func (s *Scanner) TokenText() string
TokenText 返回最近扫描的词法记号对应的字符串。 在调用 Scanner.Scan 之后以及在 Scanner.Error 调用中有效。