1

我试图了解 grep 在此示例中的工作原理。该代码有效,但我不能 100% 确定事件发生的顺序,或者我是否正确理解何时何地返回的内容。

cars = [:Ford, :Toyota, :Audi, :Honda]
ucased_cars = cars.collect do |c| 
c.to_s 
end
.grep(/^Ford/) do |car| 
puts car.upcase 
car.upcase 
end
puts "ucased:" + ucased_cars.to_s

我认为正在发生的是:

  1. 我定义了一个符号数组
  2. 我用一个块调用 collect 方法,该块导致汽车数组的每个符号元素 c 被转换为块内的字符串。
  3. collect 返回一个字符串数组
  4. grep 在 collect 返回的字符串数组上调用,并且 grep 在每个数组元素 car 上调用自己的块,匹配搜索模式,导致元素被打印、大写并作为数组的一部分返回。
  5. grep 返回一个大写字符串数组,将其分配给“ucased_cars”
  6. 数组 ucased_cars 在打印之前必须转换为字符串。

就第 4 步而言,以下哪项最能描述 grep 的工作原理:

[A] grep 查找与模式匹配的所有字符串。grep 在这个匹配数组上调用块。grep 将块的结果返回给调用函数。

[B] grep 查找与模式匹配的第一个字符串。grep 调用此匹配的块。这个块的返回值暂时堆积在某个地方。grep 搜索数组的下一个元素。如果匹配,则 grep 调用此匹配的块。grep 将此块的返回值添加到返回值的临时“存储”中。grep 查看下一个数组元素,直到找不到更多匹配项。然后 grep 将堆积的返回值传递回调用函数。

我的结论:

[A] 似乎更有意义。

[B] 似乎有很多不必要的捏造,似乎没有效率或不太可能。

4

1 回答 1

12

首先,这里是 grep 的文档

让我清理你的代码并逐个解释

# 1
cars = [:Ford, :Toyota, :Audi, :Honda]

# 2
ucased_cars = cars.collect do |c| 
  c.to_s
end.grep(/^Ford/) do |car|  # 3
  puts car.upcase # 4
  car.upcase # 5
end
# 6

# 7
puts "ucased:" + ucased_cars.to_s
  1. 声明符号数组

  2. 使用 collect 将符号转换为字符串。你得到["Ford", "Toyota", "Audi", "Honda"]

  3. 将此字符串数组输入 grep。任何与正则表达式匹配的项目都/^Ford/将被馈送到块中

  4. 该块打印出它得到的大写字符串

  5. 该块返回大写的字符串,然后 grep 将其作为“匹配值”

  6. 来自 grep 的返回值(这是一个包含所有“匹配值”的数组)被分配给ucased_cars,它是["FORD"],因为这是唯一匹配正则表达式的东西。

  7. 然后它被打印出来。对数组执行 ato_s只会打印所有像这样卡在一起的元素。这不是很有用,你最好打印ucased_cars.inspect

要回答有关 grep 如何在幕后工作的问题...

上面的文档页面显示了 grep 本身的 C 源代码。它基本上是这样做的:

  • 分配一个新的 ruby​​ 数组(动态大小)
  • 调用rb_iterate遍历源代码中的每个元素,传入一些特定于 grep 的代码。
  • rb_iterate也被collect,each_with_index和一堆其他的东西使用。

正如我们知道 collect/each/etc 是如何工作的,我们不需要在源代码中做更多的探索,我们有我们的答案,它是你的 [B]。

为了更详细地解释,它这样做:

  1. 创建一个新数组来保存返回值。
  2. 从源中获取下一项
  3. 如果它与正则表达式匹配:
    • 如果给出了一个块,则调用该块,并且无论该块返回什么,都将其放入返回值中。
    • 如果没有给出块,则将该项目放入返回值中
  4. 转到 2,重复直到源中没有更多项目。

至于您对“A似乎更有意义”的评论-我不同意。

这个想法是块对每个元素做一些事情。如果它首先扫描源,然后将匹配数组传递给块,那么您的块将不得不调用each自身,这会很麻烦。

其次,效率会更低。例如,如果您的块调用return或引发错误,会发生什么?在它当前的化身中,您不必扫描源的其余部分。如果它已经预先扫描了整个源列表,那么您将浪费所有这些努力。

于 2009-03-22T19:56:30.193 回答