class StringScanner

Class StringScanner 支持将存储的字符串作为流进行处理;此代码创建一个新的 StringScanner 对象,其中包含字符串 'foobarbaz'

require 'strscan'
scanner = StringScanner.new('foobarbaz')

关于示例

此处所有示例均假定已包含 StringScanner

require 'strscan'

此处某些示例假定已定义这些常量。

MULTILINE_TEXT = <<~EOT
Go placidly amid the noise and haste,
and remember what peace there may be in silence.
EOT

HIRAGANA_TEXT = 'こんにちは'

ENGLISH_TEXT = 'Hello'

此处某些示例假定已定义某些辅助方法。

请参阅 辅助方法 中的示例。

StringScanner 对象

此代码创建一个 StringScanner 对象(我们将其简称为扫描仪),并显示其一些基本属性。

scanner = StringScanner.new('foobarbaz')
scanner.string # => "foobarbaz"
put_situation(scanner)
# Situation:
#   pos:       0
#   charpos:   0
#   rest:      "foobarbaz"
#   rest_size: 9

扫描仪具有

存储的字符串

存储的字符串是存储在 StringScanner 对象中的字符串。

以下每种方法都会设置、修改或返回存储的字符串。

Method 效果
::new(string) 为给定字符串创建一个新的扫描仪。
string=(new_string) 替换现有的存储字符串。
concat(more_string) 将一个字符串追加到现有的存储字符串。
字符串 返回存储的字符串。

位置

StringScanner 对象维护一个零基字节位置和一个零基字符位置

以下每种方法都会显式设置位置。

Method 效果
reset 将两个位置设置为零(存储字符串的开头)。
terminate 将两个位置设置为存储字符串的末尾。
pos=(new_byte_position) 设置字节位置;调整字符位置。

字节位置(位置)

字节位置(或简称为位置)是扫描仪存储字符串中字节的零基索引;对于新的 StringScanner 对象,字节位置为零。

当字节位置为

要获取或设置字节位置

许多方法使用字节位置作为查找匹配的基础;许多其他方法设置、递增或递减字节位置。

scanner = StringScanner.new('foobar')
scanner.pos # => 0
scanner.scan(/foo/) # => "foo" # Match found.
scanner.pos         # => 3     # Byte position incremented.
scanner.scan(/foo/) # => nil   # Match not found.
scanner.pos # => 3             # Byte position not changed.

一些方法会隐式修改字节位置;请参阅

这些方法的值直接来自 posstring 的值。

字符位置

字符位置是存储字符串中字符的零基索引;对于新的 StringScanner 对象,字符位置为零。

方法 charpos 返回字符位置;其值不能显式重置。

一些方法会更改(递增或重置)字符位置;请参阅

示例(字符串包含多字节字符)

scanner = StringScanner.new(ENGLISH_TEXT) # Five 1-byte characters.
scanner.concat(HIRAGANA_TEXT)             # Five 3-byte characters
scanner.string # => "Helloこんにちは"       # Twenty bytes in all.
put_situation(scanner)
# Situation:
#   pos:       0
#   charpos:   0
#   rest:      "Helloこんにちは"
#   rest_size: 20
scanner.scan(/Hello/) # => "Hello" # Five 1-byte characters.
put_situation(scanner)
# Situation:
#   pos:       5
#   charpos:   5
#   rest:      "こんにちは"
#   rest_size: 15
scanner.getch         # => "こ"    # One 3-byte character.
put_situation(scanner)
# Situation:
#   pos:       8
#   charpos:   6
#   rest:      "んにちは"
#   rest_size: 12

目标子字符串

目标子字符串是 存储的字符串 中从当前 字节位置 到存储字符串末尾的部分;它始终是

目标子字符串由方法 rest 返回,其大小由方法 rest_size 返回。

示例

scanner = StringScanner.new('foobarbaz')
put_situation(scanner)
# Situation:
#   pos:       0
#   charpos:   0
#   rest:      "foobarbaz"
#   rest_size: 9
scanner.pos = 3
put_situation(scanner)
# Situation:
#   pos:       3
#   charpos:   3
#   rest:      "barbaz"
#   rest_size: 6
scanner.pos = 9
put_situation(scanner)
# Situation:
#   pos:       9
#   charpos:   9
#   rest:      ""
#   rest_size: 0

设置目标子字符串

目标子字符串会在以下情况设置:

查询目标子字符串

此表总结了(详情和示例请参阅链接)

Method 返回
rest 目标子字符串。
rest_size 目标子字符串的大小(字节)。

搜索目标子字符串

搜索方法会检查目标子字符串,但不会推进 位置 或(隐含地)缩短目标子字符串。

此表总结了(详情和示例请参阅链接)

Method 返回 设置匹配值?
check(pattern) 匹配的前导子字符串或 nil 是。
check_until(pattern) 匹配的子字符串(任意位置)或 nil 是。
exist?(pattern) 匹配的子字符串(任意位置)的结束索引。 是。
match?(pattern) 匹配的前导子字符串的大小或 nil 是。
peek(size) 给定长度(字节)的前导子字符串。 否。
peek_byte 前导字节或 nil 否。
rest 目标子字符串(从字节位置到末尾)。 否。

遍历目标子字符串

遍历方法会检查目标子字符串,如果成功,则

此表总结了(详情和示例请参阅链接)

Method 返回 设置匹配值?
get_byte 前导字节或 nil 否。
getch 前导字符或 nil 否。
scan(pattern) 匹配的前导子字符串或 nil 是。
scan_byte 前导字节或 nil 否。
scan_until(pattern) 匹配的子字符串(任意位置)或 nil 是。
skip(pattern) 匹配的前导子字符串大小或 nil 是。
skip_until(pattern) 到匹配子字符串末尾的位置增量或 nil 是。
unscan self. 否。

查询扫描仪

以下每种方法都会查询扫描仪对象而不修改它(详情和示例请参阅链接)。

Method 返回
beginning_of_line? truefalse
charpos 字符位置。
eos? truefalse
fixed_anchor? truefalse
inspect self 的字符串表示。
pos 字节位置。
rest 目标子字符串。
rest_size 目标子字符串的大小。
字符串 存储的字符串。

匹配

StringScanner 通过 Ruby 的 Regexp 类实现模式匹配,其匹配行为与 Ruby 相同,除了 固定锚点属性 之外。

匹配器方法

每个匹配器方法都接受一个参数 pattern,并尝试在 目标子字符串 中找到匹配的子字符串。

Method 模式类型 匹配目标子字符串 成功返回值 可能更新位置?
check RegexpString 在开头。 匹配的子字符串。 否。
check_until RegexpString 任意位置。 子字符串。 否。
match? RegexpString 在开头。 匹配大小。 否。
exist? RegexpString 任意位置。 子字符串大小。 否。
scan RegexpString 在开头。 匹配的子字符串。 是。
scan_until RegexpString 任意位置。 子字符串。 是。
skip RegexpString 在开头。 匹配大小。 是。
skip_until RegexpString 任意位置。 子字符串大小。 是。


选择哪个匹配器将取决于

匹配值

StringScanner 对象中的匹配值通常包含最近一次匹配尝试的结果。

每个匹配值都可以被视为

以下每种方法都会清除匹配值。

以下每种方法都会尝试基于模式进行匹配,并要么设置匹配值(如果成功),要么清除它们(如果不成功);

基本匹配值

基本匹配值是与捕获无关的值。

以下每种方法都会返回一个基本匹配值。

Method 匹配后的返回值 无匹配时的返回值
matched? true. false.
matched_size 匹配子字符串的大小。 nil.
matched 匹配的子字符串。 nil.
pre_match 匹配子字符串之前的子字符串。 nil.
post_match 匹配子字符串之后的子字符串。 nil.


请参阅下面的示例。

捕获的匹配值

捕获的匹配值与 捕获 相关。

以下每种方法都会返回一个捕获的匹配值。

Method 匹配后的返回值 无匹配时的返回值
size 捕获的子字符串计数。 nil.
[](n) n 个捕获的子字符串。 nil.
captures 所有捕获子字符串的 Array nil.
values_at(*n) 指定捕获子字符串的 Array nil.
named_captures 命名捕获的 Hash {}.


请参阅下面的示例。

匹配值示例

成功的基于基本匹配的尝试(无捕获)

scanner = StringScanner.new('foobarbaz')
scanner.exist?(/bar/)
put_match_values(scanner)
# Basic match values:
#   matched?:       true
#   matched_size:   3
#   pre_match:      "foo"
#   matched  :      "bar"
#   post_match:     "baz"
# Captured match values:
#   size:           1
#   captures:       []
#   named_captures: {}
#   values_at:      ["bar", nil]
#   []:
#     [0]:          "bar"
#     [1]:          nil

失败的基于基本匹配的尝试(无捕获);

scanner = StringScanner.new('foobarbaz')
scanner.exist?(/nope/)
match_values_cleared?(scanner) # => true

成功的无名捕获匹配尝试

scanner = StringScanner.new('foobarbazbatbam')
scanner.exist?(/(foo)bar(baz)bat(bam)/)
put_match_values(scanner)
# Basic match values:
#   matched?:       true
#   matched_size:   15
#   pre_match:      ""
#   matched  :      "foobarbazbatbam"
#   post_match:     ""
# Captured match values:
#   size:           4
#   captures:       ["foo", "baz", "bam"]
#   named_captures: {}
#   values_at:      ["foobarbazbatbam", "foo", "baz", "bam", nil]
#   []:
#     [0]:          "foobarbazbatbam"
#     [1]:          "foo"
#     [2]:          "baz"
#     [3]:          "bam"
#     [4]:          nil

成功的命名捕获匹配尝试;除了 named_captures 外,与无名捕获的尝试相同。

scanner = StringScanner.new('foobarbazbatbam')
scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
scanner.named_captures # => {"x"=>"foo", "y"=>"baz", "z"=>"bam"}

失败的无名捕获匹配尝试

scanner = StringScanner.new('somestring')
scanner.exist?(/(foo)bar(baz)bat(bam)/)
match_values_cleared?(scanner) # => true

失败的命名捕获匹配尝试;除了 named_captures 外,与无名捕获的尝试相同。

scanner = StringScanner.new('somestring')
scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
match_values_cleared?(scanner) # => false
scanner.named_captures # => {"x"=>nil, "y"=>nil, "z"=>nil}

固定锚点属性

StringScanner 中的模式匹配与 Ruby 的相同,除了其固定锚点属性,该属性决定了 '\A' 的含义。

固定锚点属性在创建 StringScanner 对象时设置,并且不能修改(请参阅 StringScanner.new);方法 fixed_anchor? 返回设置。