Ruby正则表达式扫描vs .split方法



我试图建立一种方法,你取每个单词的第一个字母,并将其大写。我把它写成

def titleize(name)
   name.scan(/w+/) { |x| x.capitalize! }
end

就不能正常工作了。它不会大写和字母。我做了一些搜索,最终在这里找到了答案大写标题。它被写成

def titleize(name)
   name.split(" ").each { |x| x.capitalize! }.join(" ")
end

为什么我的代码没有大写呢?如果我添加一个put语句并将其写成

def titleize(name)
   name.scan(/w+/) { |x| puts x.capitalize! }
end

它会输出大写的"hi there",但是=>仍然只是"hi there",我错过了什么?

更正代码:

def titleize(name)
   name.scan(/w+/).each { |x| x.capitalize! }.join(' ')
end
p titleize("ayan roy") #=>"Ayan Roy"

让我们看看为什么你的不工作:

def titleize(name)
   name.scan(/w+/) 
end
p titleize("ayan roy") #=>["ayan", "roy"]

现在您的行name.scan(/w+/) { |x| x.capitalize! }, x被传递为"ayan", "roy"。现在看看下面的代码:

def titleize(name)
   name.scan(/w+/) { |x| p x.capitalize!  } 
end
p titleize("ayan roy")
输出:

"Ayan"
"Roy"
"ayan roy"

As String#scan说:

scan(pattern) {|match,…| block}→str -如果给定block,scan将返回调用它的receiver。这两种形式都遍历str,匹配模式(可以是Regexp或String)。对于每个匹配,生成一个结果并将其添加到结果数组中或传递到块中。

scan返回/产生新字符串,并且永远不会修改源字符串。也许你想要gsub

def titleize(name)
  name.gsub(/w+/) {|x| x.capitalize }
end

或者最好使用title gem中更正确的实现

您的代码不起作用,因为#scan返回新的String对象,这些对象是Regexp的结果并将它们传递给块。因此,在你的方法中,你本质上获得了这些新对象,通过调用#capitalize!对它们进行了变异,但之后从未在任何地方使用过它们。

你应该这样做:

def titleize(name)
  name.scan(/w+/).each { |x| x.capitalize! }.join(' ')
end

但这对我来说似乎更容易读:

def titleize2(name)
  name.split(' ').each { |w| w.capitalize! }.join(' ')
end

请注意,这些方法不会改变传递的原始参数。

无论您在块中做了什么,scan的块形式都会返回原始字符串。(我认为你可以通过直接引用它来改变块中的原始字符串,但不建议改变你正在迭代的东西。)相反,做你的split变体,但不是each,而是collect,然后是join:

name.split(" ").collect { |x| x.capitalize }.join(" ")

这也适用于包含数字和标点符号的标题。

最新更新