类 StringScanner
StringScanner
提供了对字符串进行词法扫描操作的功能。以下是一个使用示例
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
,则匹配可以在扫描指针后面的任何位置发生。在这两种情况下,扫描指针都会移动到匹配的最后一个字符之后,准备从下一个字符开始再次扫描。上面的示例演示了这一点。
方法类别¶ ↑
除了简单的扫描器之外,还有其他方法。您可以在不实际扫描的情况下提前查看字符串。您可以访问最近的匹配项。您可以修改正在扫描的字符串,重置或终止扫描器,找出或更改扫描指针的位置,跳过等等。
前进扫描指针¶ ↑
向前看¶ ↑
查找我们所在的位置¶ ↑
-
beginning_of_line?
(#bol?
)
设置我们所在的位置¶ ↑
匹配数据¶ ↑
其他¶ ↑
一些方法有别名。
公共类方法
此方法是为了向后兼容而定义的。
static VALUE strscan_s_mustc(VALUE self) { return self; }
创建一个新的 StringScanner
对象来扫描给定的 string
。
如果 fixed_anchor
为 true
,则 \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
附加到正在扫描的字符串。此方法不会影响扫描指针。
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"
返回最近匹配项中的第 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])); }
当且仅当扫描指针位于行首时返回 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; }
返回最近匹配中的子组(不包括完整匹配)。如果之前没有匹配,则返回 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; }
返回扫描指针的字符位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的大小。
简而言之,它是字符串中从 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))); }
这将返回 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); }
这将返回 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); }
将 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; }
如果扫描指针位于字符串的末尾,则返回 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; }
提前查看 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); }
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; }
扫描一个字节并返回它。此方法不区分多字节字符。另请参阅: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])); }
扫描一个字符并返回它。此方法对多字节字符敏感。
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])); }
返回一个表示 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; }
测试给定的 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); }
返回最后匹配的字符串。
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])); }
当且仅当最后一次匹配成功时返回 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; }
返回最近匹配的大小(以字节为单位),如果最近没有匹配,则返回 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]); }
返回一个匹配正则表达式的字符串变量的哈希表。
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; }
提取与 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); }
返回扫描指针的字节位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的字节大小。
简而言之,它是字符串字节的 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
设置扫描指针的字节位置。
s = StringScanner.new('test string') s.pos = 7 # -> 7 s.rest # -> "ring"
返回扫描指针的字节位置。在“重置”位置,此值为零。在“终止”位置(即字符串已耗尽),此值为字符串的字节大小。
简而言之,它是字符串字节的 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); }
设置扫描指针的字节位置。
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); }
返回最后一次扫描的后匹配(在正则表达式意义上)。
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)); }
返回最后一次扫描的前匹配(在正则表达式意义上)。
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])); }
重置扫描指针(索引 0)并清除匹配数据。
static VALUE strscan_reset(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); p->curr = 0; CLEAR_MATCH_STATUS(p); return self; }
返回字符串的“剩余部分”(即扫描指针之后的所有内容)。如果没有更多数据(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)); }
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); }
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); }
尝试在当前位置使用 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); }
测试给定的 pattern
是否从当前扫描指针开始匹配。如果 advance_pointer_p
为 true,则前进扫描指针。如果 return_string_p
为 true,则返回匹配的字符串。匹配寄存器会受到影响。
“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); }
扫描字符串,直到匹配到 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); }
扫描字符串,直到匹配到 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); }
返回最近一次匹配的子组数量。完整匹配算作一个子组。
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); }
尝试从扫描指针开始跳过给定的 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); }
将扫描指针向前移动,直到匹配到 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); }
返回正在扫描的字符串。
static VALUE strscan_get_string(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return p->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; }
将扫描指针设置为字符串末尾并清除匹配数据。
static VALUE strscan_terminate(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); p->curr = S_LEN(p); CLEAR_MATCH_STATUS(p); return self; }
将扫描指针设置为上一个位置。仅记住一个上一个位置,并且它会随着每次扫描操作而改变。
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; }
返回最近匹配中给定索引处的子组。如果之前没有匹配,则返回 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; }
私有实例方法
复制一个 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; }