类 StringScanner

StringScanner 提供了对 String 进行词法扫描操作的功能。以下是一个使用示例

require 'strscan'

s = StringScanner.new('This is an example string')
s.eos?               # -> false

p s.scan(/\w+/)      # -> "This"
p s.scan(/\w+/)      # -> nil
p s.scan(/\s+/)      # -> " "
p s.scan(/\s+/)      # -> nil
p s.scan(/\w+/)      # -> "is"
s.eos?               # -> false

p s.scan(/\s+/)      # -> " "
p s.scan(/\w+/)      # -> "an"
p s.scan(/\s+/)      # -> " "
p s.scan(/\w+/)      # -> "example"
p s.scan(/\s+/)      # -> " "
p s.scan(/\w+/)      # -> "string"
s.eos?               # -> true

p s.scan(/\s+/)      # -> nil
p s.scan(/\w+/)      # -> nil

扫描字符串意味着记住一个扫描指针的位置,它只是一个索引。扫描的目的是一次向前移动一小段距离,因此匹配是在扫描指针之后进行的;通常是在扫描指针之后立即进行。

给定字符串“test string”,以下是相关的扫描指针位置

  t e s t   s t r i n g
0 1 2 ...             1
                      0

当你使用 scan 查找模式(正则表达式)时,匹配必须发生在扫描指针之后的字符处。如果你使用 scan_until,那么匹配可以在扫描指针之后的任何位置发生。在这两种情况下,扫描指针都会越过匹配的最后一个字符,准备从下一个字符开始再次扫描。上面的例子演示了这一点。

Method 类别

除了简单的扫描器之外,还有其他方法。您可以提前查看字符串,而无需实际扫描。您可以访问最近的匹配项。您可以修改正在扫描的字符串,重置或终止扫描器,找出或更改扫描指针的位置,跳过等等。

前进扫描指针

提前查看

查找当前位置

设置当前位置

匹配 Data

其他

一些方法有别名。

公共类方法

must_C_version click to toggle source

此方法是为了向后兼容而定义的。

static VALUE
strscan_s_mustc(VALUE self)
{
    return self;
}
new(string, fixed_anchor: false) click to toggle source
new(string, dup = false)

创建一个新的 StringScanner 对象来扫描给定的 string

如果 fixed_anchortrue,则 \A 始终匹配字符串的开头。否则,\A 始终匹配当前位置。

dup 参数已过时,现在不再使用。

static VALUE
strscan_initialize(int argc, VALUE *argv, VALUE self)
{
    struct strscanner *p;
    VALUE str, options;

    p = check_strscan(self);
    rb_scan_args(argc, argv, "11", &str, &options);
    options = rb_check_hash_type(options);
    if (!NIL_P(options)) {
        VALUE fixed_anchor;
        ID keyword_ids[1];
        keyword_ids[0] = rb_intern("fixed_anchor");
        rb_get_kwargs(options, keyword_ids, 0, 1, &fixed_anchor);
        if (fixed_anchor == Qundef) {
            p->fixed_anchor_p = false;
        }
        else {
            p->fixed_anchor_p = RTEST(fixed_anchor);
        }
    }
    else {
        p->fixed_anchor_p = false;
    }
    StringValue(str);
    p->str = str;

    return self;
}

公共实例方法

<<(str)

str 追加到正在扫描的字符串。此方法不会影响扫描指针。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/Fri /)
s << " +1000 GMT"
s.string            # -> "Fri Dec 12 1975 14:39 +1000 GMT"
s.scan(/Dec/)       # -> "Dec"
别名:concat
[](n) click to toggle source

返回最近匹配项中的第 n 个子组。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
s[0]                               # -> "Fri Dec 12 "
s[1]                               # -> "Fri"
s[2]                               # -> "Dec"
s[3]                               # -> "12"
s.post_match                       # -> "1975 14:39"
s.pre_match                        # -> ""

s.reset
s.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /)       # -> "Fri Dec 12 "
s[0]                               # -> "Fri Dec 12 "
s[1]                               # -> "Fri"
s[2]                               # -> "Dec"
s[3]                               # -> "12"
s[:wday]                           # -> "Fri"
s[:month]                          # -> "Dec"
s[:day]                            # -> "12"
s.post_match                       # -> "1975 14:39"
s.pre_match                        # -> ""
static VALUE
strscan_aref(VALUE self, VALUE idx)
{
    const char *name;
    struct strscanner *p;
    long i;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p))        return Qnil;

    switch (TYPE(idx)) {
        case T_SYMBOL:
            idx = rb_sym2str(idx);
            /* fall through */
        case T_STRING:
            if (!RTEST(p->regex)) return Qnil;
            RSTRING_GETMEM(idx, name, i);
            i = name_to_backref_number(&(p->regs), p->regex, name, name + i, rb_enc_get(idx));
            break;
        default:
            i = NUM2LONG(idx);
    }

    if (i < 0)
        i += p->regs.num_regs;
    if (i < 0)                 return Qnil;
    if (i >= p->regs.num_regs) return Qnil;
    if (p->regs.beg[i] == -1)  return Qnil;

    return extract_range(p,
                         adjust_register_position(p, p->regs.beg[i]),
                         adjust_register_position(p, p->regs.end[i]));
}
beginning_of_line?() 点击切换源代码

当且仅当扫描指针位于行首时返回 true

s = StringScanner.new("test\ntest\n")
s.bol?           # => true
s.scan(/te/)
s.bol?           # => false
s.scan(/st\n/)
s.bol?           # => true
s.terminate
s.bol?           # => true
static VALUE
strscan_bol_p(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (CURPTR(p) > S_PEND(p)) return Qnil;
    if (p->curr == 0) return Qtrue;
    return (*(CURPTR(p) - 1) == '\n') ? Qtrue : Qfalse;
}
captures 点击切换源代码

返回最近匹配中的子组(不包括完整匹配)。如果之前没有匹配,则返回 nil。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
s.captures                         # -> ["Fri", "Dec", "12"]
s.scan(/(\w+) (\w+) (\d+) /)       # -> nil
s.captures                         # -> nil
static VALUE
strscan_captures(VALUE self)
{
    struct strscanner *p;
    int   i, num_regs;
    VALUE new_ary;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p))        return Qnil;

    num_regs = p->regs.num_regs;
    new_ary  = rb_ary_new2(num_regs);

    for (i = 1; i < num_regs; i++) {
        VALUE str = extract_range(p,
                                  adjust_register_position(p, p->regs.beg[i]),
                                  adjust_register_position(p, p->regs.end[i]));
        rb_ary_push(new_ary, str);
    }

    return new_ary;
}
charpos() 点击切换源代码

返回扫描指针的字符位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的大小。

简而言之,它是一个从 0 开始的字符串索引。

s = StringScanner.new("abc\u00e4def\u00f6ghi")
s.charpos                # -> 0
s.scan_until(/\u00e4/)   # -> "abc\u00E4"
s.pos                    # -> 5
s.charpos                # -> 4
static VALUE
strscan_get_charpos(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);

    return LONG2NUM(rb_enc_strlen(S_PBEG(p), CURPTR(p), rb_enc_get(p->str)));
}
check(pattern) 点击切换源代码

此方法返回 scan 将返回的值,但不移动扫描指针。不过,匹配寄存器会受到影响。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.check /Fri/               # -> "Fri"
s.pos                       # -> 0
s.matched                   # -> "Fri"
s.check /12/                # -> nil
s.matched                   # -> nil

助记符:它“检查”以查看 scan 是否会返回值。

static VALUE
strscan_check(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 0, 1, 1);
}
check_until(pattern) 点击切换源代码

此方法返回 scan_until 将返回的值,但不移动扫描指针。不过,匹配寄存器会受到影响。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.check_until /12/          # -> "Fri Dec 12"
s.pos                       # -> 0
s.matched                   # -> 12

助记符:它“检查”以查看 scan_until 是否会返回值。

static VALUE
strscan_check_until(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 0, 1, 0);
}
clear() 点击切换源代码

等效于 terminate。此方法已过时;请改用 terminate

static VALUE
strscan_clear(VALUE self)
{
    rb_warning("StringScanner#clear is obsolete; use #terminate instead");
    return strscan_terminate(self);
}
concat(str) 点击切换源代码

str 追加到正在扫描的字符串。此方法不会影响扫描指针。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/Fri /)
s << " +1000 GMT"
s.string            # -> "Fri Dec 12 1975 14:39 +1000 GMT"
s.scan(/Dec/)       # -> "Dec"
static VALUE
strscan_concat(VALUE self, VALUE str)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    StringValue(str);
    rb_str_append(p->str, str);
    return self;
}
也称为:<<
empty?() 点击切换源代码

等效于 eos?。此方法已过时,请改用 eos?

static VALUE
strscan_empty_p(VALUE self)
{
    rb_warning("StringScanner#empty? is obsolete; use #eos? instead");
    return strscan_eos_p(self);
}
eos?() 点击切换源代码

当扫描指针位于字符串末尾时返回 true

s = StringScanner.new('test string')
p s.eos?          # => false
s.scan(/test/)
p s.eos?          # => false
s.terminate
p s.eos?          # => true
static VALUE
strscan_eos_p(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    return EOS_P(p) ? Qtrue : Qfalse;
}
exist?(pattern) 点击切换源代码

向前查看字符串中是否存在pattern,但不移动扫描指针。这可以预测scan_until是否会返回值。

s = StringScanner.new('test string')
s.exist? /s/            # -> 3
s.scan /test/           # -> "test"
s.exist? /s/            # -> 2
s.exist? /e/            # -> nil
static VALUE
strscan_exist_p(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 0, 0, 0);
}
fixed_anchor? → true 或 false 点击切换源代码

scanner 是否使用固定锚点模式。

如果使用固定锚点模式,\A 始终匹配字符串的开头。否则,\A 始终匹配当前位置。

static VALUE
strscan_fixed_anchor_p(VALUE self)
{
    struct strscanner *p;
    p = check_strscan(self);
    return p->fixed_anchor_p ? Qtrue : Qfalse;
}
get_byte() 点击切换源代码

扫描一个字节并返回它。此方法不区分多字节字符。另请参见:getch

s = StringScanner.new('ab')
s.get_byte         # => "a"
s.get_byte         # => "b"
s.get_byte         # => nil

s = StringScanner.new("\244\242".force_encoding("euc-jp"))
s.get_byte         # => "\xA4"
s.get_byte         # => "\xA2"
s.get_byte         # => nil
static VALUE
strscan_get_byte(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    CLEAR_MATCH_STATUS(p);
    if (EOS_P(p))
        return Qnil;

    p->prev = p->curr;
    p->curr++;
    MATCHED(p);
    adjust_registers_to_matched(p);
    return extract_range(p,
                         adjust_register_position(p, p->regs.beg[0]),
                         adjust_register_position(p, p->regs.end[0]));
}
getbyte() 点击切换源代码

等效于 get_byte。此方法已过时;请使用 get_byte

static VALUE
strscan_getbyte(VALUE self)
{
    rb_warning("StringScanner#getbyte is obsolete; use #get_byte instead");
    return strscan_get_byte(self);
}
getch() 点击切换源代码

扫描一个字符并返回它。此方法区分多字节字符。

s = StringScanner.new("ab")
s.getch           # => "a"
s.getch           # => "b"
s.getch           # => nil

s = StringScanner.new("\244\242".force_encoding("euc-jp"))
s.getch           # => "\x{A4A2}"   # Japanese hira-kana "A" in EUC-JP
s.getch           # => nil
static VALUE
strscan_getch(VALUE self)
{
    struct strscanner *p;
    long len;

    GET_SCANNER(self, p);
    CLEAR_MATCH_STATUS(p);
    if (EOS_P(p))
        return Qnil;

    len = rb_enc_mbclen(CURPTR(p), S_PEND(p), rb_enc_get(p->str));
    len = minl(len, S_RESTLEN(p));
    p->prev = p->curr;
    p->curr += len;
    MATCHED(p);
    adjust_registers_to_matched(p);
    return extract_range(p,
                         adjust_register_position(p, p->regs.beg[0]),
                         adjust_register_position(p, p->regs.end[0]));
}
inspect() 点击切换源代码

返回一个字符串,表示 StringScanner 对象,显示

  • 当前位置

  • 字符串的大小

  • 扫描指针周围的字符

    s = StringScanner.new(“Fri Dec 12 1975 14:39”) s.inspect # -> ‘#<StringScanner 0/21 @ “Fri D…”>’ s.scan_until /12/ # -> “Fri Dec 12” s.inspect # -> ‘#<StringScanner 10/21 “…ec 12” @ “ 1975…”>’

static VALUE
strscan_inspect(VALUE self)
{
    struct strscanner *p;
    VALUE a, b;

    p = check_strscan(self);
    if (NIL_P(p->str)) {
        a = rb_sprintf("#<%"PRIsVALUE" (uninitialized)>", rb_obj_class(self));
        return a;
    }
    if (EOS_P(p)) {
        a = rb_sprintf("#<%"PRIsVALUE" fin>", rb_obj_class(self));
        return a;
    }
    if (p->curr == 0) {
        b = inspect2(p);
        a = rb_sprintf("#<%"PRIsVALUE" %ld/%ld @ %"PRIsVALUE">",
                       rb_obj_class(self),
                       p->curr, S_LEN(p),
                       b);
        return a;
    }
    a = inspect1(p);
    b = inspect2(p);
    a = rb_sprintf("#<%"PRIsVALUE" %ld/%ld %"PRIsVALUE" @ %"PRIsVALUE">",
                   rb_obj_class(self),
                   p->curr, S_LEN(p),
                   a, b);
    return a;
}
match?(pattern) 点击切换源代码

测试给定的 pattern 是否从当前扫描指针开始匹配。返回匹配的长度,或 nil。扫描指针不会移动。

s = StringScanner.new('test string')
p s.match?(/\w+/)   # -> 4
p s.match?(/\w+/)   # -> 4
p s.match?("test")  # -> 4
p s.match?(/\s+/)   # -> nil
static VALUE
strscan_match_p(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 0, 0, 1);
}
matched() 点击切换源代码

返回最后匹配的字符串。

s = StringScanner.new('test string')
s.match?(/\w+/)     # -> 4
s.matched           # -> "test"
static VALUE
strscan_matched(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p)) return Qnil;
    return extract_range(p,
                         adjust_register_position(p, p->regs.beg[0]),
                         adjust_register_position(p, p->regs.end[0]));
}
matched?() 点击切换源代码

当且仅当最后一次匹配成功时返回 true

s = StringScanner.new('test string')
s.match?(/\w+/)     # => 4
s.matched?          # => true
s.match?(/\d+/)     # => nil
s.matched?          # => false
static VALUE
strscan_matched_p(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    return MATCHED_P(p) ? Qtrue : Qfalse;
}
matched_size() 点击切换源代码

返回最近匹配的大小(以字节为单位),如果最近没有匹配,则返回 nil。这与 matched.size 不同,后者将返回字符的大小。

s = StringScanner.new('test string')
s.check /\w+/           # -> "test"
s.matched_size          # -> 4
s.check /\d+/           # -> nil
s.matched_size          # -> nil
static VALUE
strscan_matched_size(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p)) return Qnil;
    return LONG2NUM(p->regs.end[0] - p->regs.beg[0]);
}
named_captures → hash 点击切换源代码

返回与正则表达式匹配的字符串变量的哈希表。

scan = StringScanner.new('foobarbaz')
scan.match?(/(?<f>foo)(?<r>bar)(?<z>baz)/)
scan.named_captures # -> {"f"=>"foo", "r"=>"bar", "z"=>"baz"}
static VALUE
strscan_named_captures(VALUE self)
{
    struct strscanner *p;
    GET_SCANNER(self, p);
    named_captures_data data;
    data.self = self;
    data.captures = rb_hash_new();
    if (!RB_NIL_P(p->regex)) {
        onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);
    }

    return data.captures;
}
peek(len) 点击切换源代码

提取与 string[pos,len] 对应的字符串,但不移动扫描指针。

s = StringScanner.new('test string')
s.peek(7)          # => "test st"
s.peek(7)          # => "test st"
static VALUE
strscan_peek(VALUE self, VALUE vlen)
{
    struct strscanner *p;
    long len;

    GET_SCANNER(self, p);

    len = NUM2LONG(vlen);
    if (EOS_P(p))
        return str_new(p, "", 0);

    len = minl(len, S_RESTLEN(p));
    return extract_beg_len(p, p->curr, len);
}
peep(p1) 点击切换源代码

等效于 peek。此方法已过时;请使用 peek 代替。

static VALUE
strscan_peep(VALUE self, VALUE vlen)
{
    rb_warning("StringScanner#peep is obsolete; use #peek instead");
    return strscan_peek(self, vlen);
}
pointer()

返回扫描指针的字节位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的字节大小。

简而言之,它是字符串字节的 0 索引。

s = StringScanner.new('test string')
s.pos               # -> 0
s.scan_until /str/  # -> "test str"
s.pos               # -> 8
s.terminate         # -> #<StringScanner fin>
s.pos               # -> 11
别名:pos
pointer=
别名:pos=
pos() 点击切换源代码

返回扫描指针的字节位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的字节大小。

简而言之,它是字符串字节的 0 索引。

s = StringScanner.new('test string')
s.pos               # -> 0
s.scan_until /str/  # -> "test str"
s.pos               # -> 8
s.terminate         # -> #<StringScanner fin>
s.pos               # -> 11
static VALUE
strscan_get_pos(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    return INT2FIX(p->curr);
}
也称为:pointer
pos=(n) 点击切换源代码

设置扫描指针的字节位置。

s = StringScanner.new('test string')
s.pos = 7            # -> 7
s.rest               # -> "ring"
static VALUE
strscan_set_pos(VALUE self, VALUE v)
{
    struct strscanner *p;
    long i;

    GET_SCANNER(self, p);
    i = NUM2INT(v);
    if (i < 0) i += S_LEN(p);
    if (i < 0) rb_raise(rb_eRangeError, "index out of range");
    if (i > S_LEN(p)) rb_raise(rb_eRangeError, "index out of range");
    p->curr = i;
    return LONG2NUM(i);
}
也称为:pointer=
post_match() 点击切换源代码

返回上次扫描的匹配(在正则表达式意义上)。

s = StringScanner.new('test string')
s.scan(/\w+/)           # -> "test"
s.scan(/\s+/)           # -> " "
s.pre_match             # -> "test"
s.post_match            # -> "string"
static VALUE
strscan_post_match(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p)) return Qnil;
    return extract_range(p,
                         adjust_register_position(p, p->regs.end[0]),
                         S_LEN(p));
}
pre_match() 点击切换源代码

返回上次扫描的匹配(在正则表达式意义上)。

s = StringScanner.new('test string')
s.scan(/\w+/)           # -> "test"
s.scan(/\s+/)           # -> " "
s.pre_match             # -> "test"
s.post_match            # -> "string"
static VALUE
strscan_pre_match(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p)) return Qnil;
    return extract_range(p,
                         0,
                         adjust_register_position(p, p->regs.beg[0]));
}
reset() 点击切换源代码

重置扫描指针(索引 0)并清除匹配数据。

static VALUE
strscan_reset(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    p->curr = 0;
    CLEAR_MATCH_STATUS(p);
    return self;
}
rest() 点击切换源代码

返回字符串的“剩余部分”(即扫描指针之后的所有内容)。如果没有更多数据(eos?= true),则返回 ""

static VALUE
strscan_rest(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (EOS_P(p)) {
        return str_new(p, "", 0);
    }
    return extract_range(p, p->curr, S_LEN(p));
}
rest?() 点击切换源代码

当且仅当字符串中还有更多数据时返回 true。参见 eos?。此方法已过时;请使用 eos? 代替。

s = StringScanner.new('test string')
# These two are opposites
s.eos? # => false
s.rest? # => true
static VALUE
strscan_rest_p(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    return EOS_P(p) ? Qfalse : Qtrue;
}
rest_size() 点击切换源代码

s.rest_size 等效于 s.rest.size

static VALUE
strscan_rest_size(VALUE self)
{
    struct strscanner *p;
    long i;

    GET_SCANNER(self, p);
    if (EOS_P(p)) {
        return INT2FIX(0);
    }
    i = S_RESTLEN(p);
    return INT2FIX(i);
}
restsize() 点击切换源代码

s.restsize 等效于 s.rest_size。此方法已过时;请使用 rest_size 代替。

static VALUE
strscan_restsize(VALUE self)
{
    rb_warning("StringScanner#restsize is obsolete; use #rest_size instead");
    return strscan_rest_size(self);
}
scan(pattern) → String 点击切换源代码

尝试从当前位置匹配 pattern。如果匹配,扫描器将“扫描指针”向前移动并返回匹配的字符串。否则,扫描器将返回 nil

s = StringScanner.new('test string')
p s.scan(/\w+/)   # -> "test"
p s.scan(/\w+/)   # -> nil
p s.scan(/\s+/)   # -> " "
p s.scan("str")   # -> "str"
p s.scan(/\w+/)   # -> "ing"
p s.scan(/./)     # -> nil
static VALUE
strscan_scan(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 1, 1, 1);
}
scan_full(pattern, advance_pointer_p, return_string_p) 点击切换源代码

测试给定的 pattern 是否从当前扫描指针开始匹配。如果 advance_pointer_p 为真,则向前移动扫描指针。如果 return_string_p 为真,则返回匹配的字符串。匹配寄存器会受到影响。

“full” 表示“#scan with full parameters”。

static VALUE
strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f)
{
    return strscan_do_scan(self, re, RTEST(s), RTEST(f), 1);
}
scan_until(pattern) 点击切换源代码

扫描字符串,直到匹配到 pattern。返回直到匹配结束(包括匹配结束)的子字符串,并将扫描指针移动到该位置。如果未匹配,则返回 nil

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan_until(/1/)        # -> "Fri Dec 1"
s.pre_match              # -> "Fri Dec "
s.scan_until(/XYZ/)      # -> nil
static VALUE
strscan_scan_until(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 1, 1, 0);
}
search_full(pattern, advance_pointer_p, return_string_p) 点击切换源代码

扫描字符串,直到匹配到 pattern。如果 advance_pointer_p 为真,则向前移动扫描指针,否则不移动。如果 return_string_p 为真,则返回匹配的字符串,否则返回移动的字节数。此方法会影响匹配寄存器。

static VALUE
strscan_search_full(VALUE self, VALUE re, VALUE s, VALUE f)
{
    return strscan_do_scan(self, re, RTEST(s), RTEST(f), 0);
}
size 点击切换源代码

返回最近一次匹配中的子组数量。完整匹配算作一个子组。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
s.size                             # -> 4
static VALUE
strscan_size(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p))        return Qnil;
    return INT2FIX(p->regs.num_regs);
}
skip(pattern) 点击切换源代码

尝试从扫描指针开始跳过给定的 pattern。如果匹配,则将扫描指针移动到匹配结束,并返回匹配的长度。否则,返回 nil

它类似于 scan,但不会返回匹配的字符串。

s = StringScanner.new('test string')
p s.skip(/\w+/)   # -> 4
p s.skip(/\w+/)   # -> nil
p s.skip(/\s+/)   # -> 1
p s.skip("st")    # -> 2
p s.skip(/\w+/)   # -> 4
p s.skip(/./)     # -> nil
static VALUE
strscan_skip(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 1, 0, 1);
}
skip_until(pattern) 点击切换源代码

向前移动扫描指针,直到匹配到 pattern 并将其消耗。返回移动的字节数,如果未找到匹配项,则返回 nil

向前查看以匹配pattern,并将扫描指针移至匹配的末尾。返回已前进的字符数,如果匹配不成功则返回nil

它类似于scan_until,但不会返回中间的字符串。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.skip_until /12/           # -> 10
s                           #
static VALUE
strscan_skip_until(VALUE self, VALUE re)
{
    return strscan_do_scan(self, re, 1, 0, 0);
}
string() 点击切换源代码

返回正在扫描的字符串。

static VALUE
strscan_get_string(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    return p->str;
}
string=(str) 点击切换源代码

将正在扫描的字符串更改为str并重置扫描器。返回str

static VALUE
strscan_set_string(VALUE self, VALUE str)
{
    struct strscanner *p = check_strscan(self);

    StringValue(str);
    p->str = str;
    p->curr = 0;
    CLEAR_MATCH_STATUS(p);
    return str;
}
terminate 点击切换源代码
清除

将扫描指针设置为字符串的末尾并清除匹配数据。

static VALUE
strscan_terminate(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    p->curr = S_LEN(p);
    CLEAR_MATCH_STATUS(p);
    return self;
}
unscan() 点击切换源代码

将扫描指针设置为上一个位置。只记住一个上一个位置,它会随着每次扫描操作而改变。

s = StringScanner.new('test string')
s.scan(/\w+/)        # => "test"
s.unscan
s.scan(/../)         # => "te"
s.scan(/\d/)         # => nil
s.unscan             # ScanError: unscan failed: previous match record not exist
static VALUE
strscan_unscan(VALUE self)
{
    struct strscanner *p;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p))
        rb_raise(ScanError, "unscan failed: previous match record not exist");
    p->curr = p->prev;
    CLEAR_MATCH_STATUS(p);
    return self;
}
values_at( i1, i2, ... iN ) → an_array 点击切换源代码

返回最近匹配中给定索引处的子组。如果之前没有匹配,则返回 nil。

s = StringScanner.new("Fri Dec 12 1975 14:39")
s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
s.values_at 0, -1, 5, 2            # -> ["Fri Dec 12 ", "12", nil, "Dec"]
s.scan(/(\w+) (\w+) (\d+) /)       # -> nil
s.values_at 0, -1, 5, 2            # -> nil
static VALUE
strscan_values_at(int argc, VALUE *argv, VALUE self)
{
    struct strscanner *p;
    long i;
    VALUE new_ary;

    GET_SCANNER(self, p);
    if (! MATCHED_P(p))        return Qnil;

    new_ary = rb_ary_new2(argc);
    for (i = 0; i<argc; i++) {
        rb_ary_push(new_ary, strscan_aref(self, argv[i]));
    }

    return new_ary;
}

私有实例方法

dup 点击切换源代码
克隆

复制一个StringScanner对象。

static VALUE
strscan_init_copy(VALUE vself, VALUE vorig)
{
    struct strscanner *self, *orig;

    self = check_strscan(vself);
    orig = check_strscan(vorig);
    if (self != orig) {
        self->flags = orig->flags;
        self->str = orig->str;
        self->prev = orig->prev;
        self->curr = orig->curr;
        if (rb_reg_region_copy(&self->regs, &orig->regs))
            rb_memerror();
        RB_GC_GUARD(vorig);
    }

    return vself;
}