2016-01-09 13 views
8

Nếu tôi làm một trận đấu với một biểu thức chính quy với mười chụp:Tại sao chỉ một số lượng hạn chế các biểu thức chính quy được lưu trữ trong `global_variables`?

/(o)(t)(th)(f)(fi)(s)(se)(e)(n)(t)/.match("otthffisseent") 

sau đó, cho $10, tôi nhận được:

$10 # => "t" 

nhưng nó là mất tích từ global_variables. Tôi nhận được (trong một phiên IRB):

[:$;, :$-F, :[email protected], :$!, :$SAFE, :$~, :$&, :$`, :$', :$+, :$=, :$KCODE, :$-K, :$,, 
:$/, :$-0, :$\, :$_, :$stdin, :$stdout, :$stderr, :$>, :$<, :$., :$FILENAME, 
:$-i, :$*, :$?, :$$, :$:, :$-I, :$LOAD_PATH, :$", :$LOADED_FEATURES, 
:$VERBOSE, :$-v, :$-w, :$-W, :$DEBUG, :$-d, :$0, :$PROGRAM_NAME, :$-p, :$-l, 
:$-a, :$binding, :$1, :$2, :$3, :$4, :$5, :$6, :$7, :$8, :$9] 

Ở đây, chỉ có chín đầu tiên được liệt kê:

$1, :$2, :$3, :$4, :$5, :$6, :$7, :$8, :$9 

này cũng được xác nhận bởi:

global_variables.include?(:$10) # => false 

đâu $10 lưu trữ, và tại sao nó không được lưu trữ trong global_variables?

+1

Bạn có thể sử dụng '$ ~' chứa đối tượng MatchData, qua đó bạn có thể truy cập tất cả các kết quả bắt đầu bằng chỉ mục 1. –

+2

@TamerShlash bạn cũng có thể sử dụng '$ 10', nhưng điều đó không giải thích được biến toàn cục đó là được lưu trữ và tại sao nó bị thiếu trong 'global_variables' – Stefan

+0

Đúng vậy, tôi đã đọc sai câu hỏi. –

Trả lời

6

Biến số được trả lại từ Kernel#global_variables sẽ luôn giống nhau, ngay cả trước khi được chỉ định. I E. $1 thông qua $9 sẽ được trả lại ngay cả trước khi bạn thực hiện trận đấu và kết hợp nhiều hơn sẽ không thêm vào danh sách. (Họ có thể cũng không được chỉ định, ví dụ như sử dụng $10 = "foo".)

Hãy xem xét các mã nguồn cho phương pháp:

VALUE 
rb_f_global_variables(void) 
{ 
    VALUE ary = rb_ary_new(); 
    char buf[2]; 
    int i; 

    st_foreach_safe(rb_global_tbl, gvar_i, ary); 
    buf[0] = '$'; 

    for (i = 1; i <= 9; ++i) { 
     buf[1] = (char)(i + '0'); 
     rb_ary_push(ary, ID2SYM(rb_intern2(buf, 2))); 
    } 

    return ary; 
} 

Bạn có thể (sau khi đã làm quen với việc nhìn vào C) nhìn thấy từ vòng lặp for rằng các ký hiệu $1 đến $9 được mã hóa cứng thành giá trị trả về của phương thức.

Vậy làm thế nào sau đó, bạn vẫn có thể sử dụng $10, nếu đầu ra của global_variables không thay đổi? Vâng, đầu ra có thể gây nhầm lẫn một chút, vì nó sẽ gợi ý dữ liệu đối sánh của bạn được lưu trữ trong các biến riêng biệt, nhưng đây chỉ là các phím tắt, ủy quyền cho đối tượng MatchData được lưu trữ trong $~.

Về cơ bản $n xem $~[n]. Bạn sẽ tìm thấy đối tượng MatchData này (đến từ bảng toàn cầu) là một phần của đầu ra ban đầu từ phương thức, nhưng nó không được gán cho đến khi bạn thực hiện một kết quả phù hợp.

Đối với những gì biện minh cho việc bao gồm $1 thông qua $9 trong đầu ra của hàm, bạn sẽ cần hỏi ai đó trong nhóm lõi Ruby. Nó có vẻ có vẻ tùy ý, nhưng có khả năng một số thảo luận đã đi vào quyết định.

+0

* "Các giá trị được trả về từ Kernel # global_variables sẽ luôn giống nhau" * - Điều này không đúng. Nếu tôi làm '$ foo = 1', thì' $ foo' sẽ được thêm vào 'global_variables'. – sawa

+0

@sawa: Tốt. Đã sửa. – Drenmi

+1

Một bí ẩn còn lại - làm thế nào là '$ 10' được đánh giá nếu nó không phải là biến toàn cầu –

9

của Ruby dường như để xử lý $1, $2, vv ở cấp phân tích cú pháp:

ruby --dump parsetree_with_comment -e '$100' 

Output:

########################################################### 
## Do NOT use this node dump for any purpose other than ## 
## debug and research. Compatibility is not guaranteed. ## 
########################################################### 

# @ NODE_SCOPE (line: 1) 
# | # new scope 
# | # format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body 
# +- nd_tbl (local table): (empty) 
# +- nd_args (arguments): 
# | (null node) 
# +- nd_body (body): 
#  @ NODE_NTH_REF (line: 1) 
#  | # nth special variable reference 
#  | # format: $[nd_nth] 
#  | # example: $1, $2, .. 
#  +- nd_nth (variable): $100 

BTW, maximum number of capture groups là 32,767 và bạn có thể truy cập tất cả thông qua $n:

/#{'()' * 32768}/  #=> RegexpError: too many capture groups are specified 

/#{'()' * 32767}/ =~ '' #=> 0 
defined? $32767   #=> "global-variable" 
$32767     #=> "" 
+1

Đẹp! Đây là phần bổ sung mà câu trả lời của tôi cần. :-) – Drenmi

+2

Sức mạnh tuyệt vời của Ruby. Tôi sẽ không bao giờ chạy ra khỏi nhóm chụp. – sawa

+3

[PCRE2 hỗ trợ 65.535 nhóm chụp] (http://stackoverflow.com/a/33928343/3832970), vì vậy nó đánh bại Ruby :) Tuy nhiên, tôi nghi ngờ bạn sẽ bao giờ sử dụng hơn 99, trong cuộc sống thực, chúng tôi muốn nhận được nhiều kết quả so với cố gắng nắm bắt tất cả các chi tiết với một regex khó sử dụng. –

3

chúng tôi xem xét t hành vi của mình như là một lỗi. Chúng tôi đã sửa lỗi này trong thân cây.

+1

Bạn có phải là nhà phát triển về dự án được đề cập không? Bạn có thể nói điều gì đó về điều đó, hoặc bằng cách nào đó giải thích về ý của bạn. Có lẽ phiên bản nào sẽ sửa chữa hoặc sửa lỗi? – melwil

+0

@melwil, lols. vâng, anh ấy có thể đã tạo ra ngôn ngữ ... – Intentss

Các vấn đề liên quan