...

パッケージ scanner

import "text/scanner"
概要
目次

概要 ▾

scanner パッケージは,UTF-8 でエンコードされたテキストをスキャンし,トークンに区切る関数を提供します。 ソースを提供する io.Reader が必要です。 これは, Scan 関数を繰り返し呼び出すことでトークン化できます。 既存のツールとの互換性のために, NUL 文字は許可されていません。 ソースの最初の文字が UTF-8 でエンコードされたバイトオーダーマーク (BOM) の場合,それは破棄されます。

デフォルトでは,スキャナは空白と Go のコメントをスキップし, Go 言語仕様で定義されているとおりにすべてのリテラルを認識します。 これらのリテラルのサブセットのみを認識し,異なる識別子と空白文字を認識するようにカスタマイズできます。

コード:

const src = `
// これはスキャンされたコードです。
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: }

例 (IsIdentRune)

コード:

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"

// 先頭の '%' を識別子の一部として扱う
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: %

例 (Mode)

コード:

const src = `
    // コメントは 5 桁目から始まります。

This line should not be included in the output.

/*
この複数行コメントは全体として抽出されるべきです。
*/
`

var s scanner.Scanner
s.Init(strings.NewReader(src))
s.Filename = "comments"
s.Mode ^= scanner.SkipComments // コメントをスキップしない

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.
*/

例 (Whitespace)

コード:

// タブ区切り値
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 // 上記の例では十分な大きさ
)
s.Init(strings.NewReader(src))
s.Whitespace ^= 1<<'\t' | 1<<'\n' // タブと改行をスキップしない

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]]

定数

トークンの認識を制御するための定義済みモードビット。 たとえば,識別子,整数,およびコメントのスキップのみを認識するようにスキャナを設定するには, [スキャナのモード] フィールドを次のように設定します。

ScanIdents | ScanInts | SkipComments

SkipComments が設定されている場合にスキップされるコメントを除いて,認識されないトークンは無視されません。 代わりに,スキャナは単にそれぞれの個々の文字 (またはおそらくサブトークン) を返します。 たとえば,モードが ScanIdents(ScanStrings ではない) の場合,文字列 "foo" がトークンシーケンス '"' Ident '"' としてスキャンされます。

GoToken を使用して, Go 識別子を含むすべての Go リテラルトークンを受け入れるように Scanner を構成します。 コメントはスキップされます。

const (
    ScanIdents     = 1 << -Ident
    ScanInts       = 1 << -Int
    ScanFloats     = 1 << -Float // Int と 16 進数 float を含む
    ScanChars      = 1 << -Char
    ScanStrings    = 1 << -String
    ScanRawStrings = 1 << -RawString
    ScanComments   = 1 << -Comment
    SkipComments   = 1 << -skipComment // ScanComments で設定した場合,コメントは空白になります
    GoTokens       = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
)

Scan の結果は,これらのトークンの 1 つ,または Unicode 文字です。

const (
    EOF = -(iota + 1)
    Ident
    Int
    Float
    Char
    String
    RawString
    Comment
)

GoWhitespace は, Scanner の Whitespace フィールドのデフォルト値です。 その値は Go の空白文字を選択します。

const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '

func TokenString

func TokenString(tok rune) string

TokenString は,トークンまたは Unicode 文字の表示可能文字列を返します。

type Position

ソース位置は Position 値で表されます。 Line > 0 の場合,位置は有効です。

type Position struct {
    Filename string // ファイル名,もしあれば
    Offset   int    // 0 から始まるバイトオフセット
    Line     int    // 1 から始まる行番号
    Column   int    // 1 から始まる列番号 (行ごとの文字カウント)
}

func (*Position) IsValid

func (pos *Position) IsValid() bool

IsValid は,位置が有効かどうかを報告します。

func (Position) String

func (pos Position) String() string

type Scanner

Scanner は, io.Reader からの Unicode 文字とトークンの読み取りを実装します。

type Scanner struct {

    // 発生したエラーごとに Error が呼び出されます。
    // Error 関数が設定されていない場合,エラーは os.Stderr に報告されます。
    Error func(s *Scanner, msg string)

    // ErrorCount は,発生したエラーごとに 1 ずつ増加します。
    ErrorCount int

    // Mode フィールドはどのトークンが認識されるかを制御します。
    // たとえば, Ints を認識するためには, Mode の ScanInts ビットをセットします。
    // このフィールドはいつでも変更できます。
    Mode uint

    // Whitespace フィールドは,どの文字が空白として認識されるかを制御します。
    // 文字 ch <= ' ' を空白として認識させるには,空白文字の ch 番目のビットを設定します (スキャナの動作は,値 ch > ' ' では未定義です) 。
    // このフィールドはいつでも変更できます。
    Whitespace uint64

    // IsIdentRune は,識別子の i 番目のルーンとして受け入れられる文字を制御する述語です。
    // 有効文字の集合は,空白文字の集合と交差してはいけません。
    // IsIdentRune 関数が設定されていない場合は,代わりに通常の Go 識別子が受け入れられます。
    // このフィールドはいつでも変更できます。
    IsIdentRune func(ch rune, i int) bool // Go 1.4

    // 最後にスキャンされたトークンの開始位置スキャンで設定します。
    // Init または Next を呼び出すと,位置が無効になります (Line == 0) 。
    // Filename フィールドは常にスキャナによって変更されません。
    // エラーが (エラーで) 報告され,位置が無効な場合,スキャナはトークンの内側にありません。
    // その場合は Pos を呼び出してエラー位置を取得するか,または最後にスキャンされたトークンの直後の位置を取得します。
    Position
    // エクスポートされていないフィールドがあります
}

func (*Scanner) Init

func (s *Scanner) Init(src io.Reader) *Scanner

Init は Scanner を新しいソースで初期化して s を返します。 Error は nil, ErrorCount は 0, Mode は GoTokens , Whitespace は GoWhitespace に設定されています。

func (*Scanner) Next

func (s *Scanner) Next() rune

Next は次の Unicode 文字を読み込んで返します。 ソースの終わりに EOF を返します。 nil でなければ s.Error を呼び出して読み込みエラーを報告します。 そうでなければ,エラーメッセージを os.Stderr に出力します。 Next は Scanner's Position フィールドを更新しません。 現在位置を取得するには Pos() を使用してください。

func (*Scanner) Peek

func (s *Scanner) Peek() rune

Peek はスキャナを進めずにソース内の次の Unicode 文字を返します。 スキャナの位置がソースの最後の文字にある場合は EOF を返します。

func (*Scanner) Pos

func (s *Scanner) Pos() (pos Position)

Pos は,最後の Next または Scan の呼び出しで返された文字またはトークンの直後の文字の位置を返します。 最後にスキャンされたトークンの開始位置には, " スキャナーの位置 " フィールドを使用してください。

func (*Scanner) Scan

func (s *Scanner) Scan() rune

Scan はソースから次のトークンまたは Unicode 文字を読み取り,それを返します。 それぞれのモードビット (1<<-t) が設定されているトークン t のみを認識します。 ソースの終わりに EOF を返します。 それは nil でなければ s.Error を呼び出すことによってスキャナエラー (読み取りとトークンエラー) を報告します。 そうでなければ,エラーメッセージを os.Stderr に出力します。

func (*Scanner) TokenText

func (s *Scanner) TokenText() string

TokenText は,最後にスキャンされたトークンに対応する文字列を返します。 Scan を呼び出した後と Scanner.Error の呼び出しで有効です。