Hai phiên bản khác nhau vì biến số $1
là chuỗi địa phương và phương pháp cục bộ.Trong ví dụ đầu tiên, $1
chỉ tồn tại trong khối bên ngoài phương thức hello
. Trong ví dụ thứ hai, $1
tồn tại bên trong phương thức hello
.
Không có cách nào để chuyển $ 1 trong khối thành gsub từ bên ngoài định nghĩa phương thức.
Lưu ý rằng gsub
chuyển chuỗi đối sánh vào khối, vì vậy z = proc { |m| pp m }
sẽ chỉ hoạt động miễn là cụm từ thông dụng của bạn chỉ chứa toàn bộ kết quả trùng khớp. Ngay khi biểu thức chính quy của bạn chứa bất kỳ thông tin nào khác ngoài tham chiếu bạn muốn, bạn sẽ không may mắn.
Ví dụ: "hello".gsub(/l(o)/) { |m| m }
=>hello
, vì toàn bộ chuỗi đối sánh được chuyển đến khối.
Trong khi đó, "hello".gsub(/l(o)/) { |m| $1 }
=>helo
, vì l
khớp với khối bị xóa, tất cả những gì chúng tôi quan tâm là bị bắt giữ o
.
Giải pháp của tôi là để match
biểu thức chính quy, sau đó vượt qua các đối tượng MatchData
vào khối:
require 'pp'
def hello(z)
string = "hello"
regex = /(o)/
m = string.match(regex)
string.gsub(regex, z.call(m))
end
z = proc { |m| pp m[1] }
pp hello(z)
Nguồn
2013-08-31 17:41:52
Ngay cả trong mã này ''hello'.gsub (/ (e) /) {đặt $ 1}' Proc.new được gọi trước gsub: đây là cách mọi ngôn ngữ lập trình hoạt động - khối là cùng một đối số với những người khác. Nó cần phải được xây dựng trước khi vượt qua nó ở đâu đó. Vì vậy, tôi không nghĩ rằng câu trả lời của bạn giải thích bất cứ điều gì –
@ BogdanGusiev 'Proc.new' được gọi trước' gsub', nhưng khối không phải là. Nó chỉ được phân tích cú pháp. Một khối không phải là một đối số. – sawa
Có, khối không được gọi trước 'gsub' trong cả hai biến thể mã. Vì vậy, sự khác biệt là số lượng các cuộc gọi để vượt qua khối để gsub: đó có thể là 1 hoặc 2. Nhưng nó vẫn không bao giờ bằng 0. '$ 1' biến không bao giờ có mặt trong bối cảnh nơi' z' được định nghĩa. Biến số –