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
,則比對可以在掃描指標之後的任何位置發生。在這兩種情況下,掃描指標會移動到比對的最後一個字元的正後方,準備從下一個字元開始再次掃描。上面的範例示範了這一點。
方法
類別¶ ↑
除了純粹的掃描器之外,還有其他方法。您可以在實際掃描之前先預覽字串。您可以存取最近的比對。您可以修改正在掃描的字串、重設或終止掃描器、找出或變更掃描指標的位置、向前跳過等。
前進掃描指標¶ ↑
預覽¶ ↑
尋找我們所在的位置¶ ↑
-
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
(“週五 12 月 1975 14:39”) s.inspect # -> ‘#<StringScanner 0/21 @ “週五 D…”>’ s.scan_until /12/ # -> “週五 12 月 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
傳回掃描指標的位元組位置。在「重設」位置,此值為零。在「終止」位置(即字串已用盡),此值為字串的位元組大小。
簡而言之,它是一個以 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
為 true,則前進掃描指標,否則不前進。如果 return_string_p
為 true,則傳回相符的字串,否則傳回前進的位元組數目。此方法會影響比對暫存器。
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; }