为什么Rails titlecase会为名称添加空格?

为什么这个titlecase搞砸这个名字? 我有:

 John Mark McMillan 

它把它变成:

 >> "john mark McMillan".titlecase => "John Mark Mc Millan" 

为什么在姓氏上添加了空格?

基本上我在我的模型中有这个:

 before_save :capitalize_name def capitalize_name self.artist = self.artist.titlecase end 

我试图确保所有名称都是数据库中的标题,但是在使用camelcase名称的情况下,它会失败。 任何想法如何解决这一问题?

如果Rails不够好,你总是可以自己做:

 class String  def another_titlecase    self.split(" ").collect{|word| word[0] = word[0].upcase; word}.join(" ")  end end "john mark McMillan".another_titlecase => "John Mark McMillan" 

这种方法比正则表达式解决方案快一小部分:

我的解决方案

 ruby-1.9.2-p136 :034 > Benchmark.ms do ruby-1.9.2-p136 :035 > "john mark McMillan".split(" ").collect{|word|word[0] = word[0].upcase; word}.join(" ") ruby-1.9.2-p136 :036?> end => 0.019311904907226562 

正则表达式解决方案:

 ruby-1.9.2-p136 :042 > Benchmark.ms do ruby-1.9.2-p136 :043 > "john mark McMillan".gsub(/\b\w/) { |w| w.upcase } ruby-1.9.2-p136 :044?> end => 0.04482269287109375 

如果您想要的是确保每个单词都以大写字母开头:

 class String def titlecase2 self.split(' ').map { |w| w[0] = w[0].upcase; w }.join(' ') end end irb(main):016:0> "john mark McMillan".titlecase2 => "John Mark McMillan" 

嗯,这很奇怪..但你可以写一个快速的自定义正则表达式,以避免使用该方法。

 class String def custom_titlecase self.gsub(/\b\w/) { |w| w.upcase } end end "John Mark McMillan".custom_titlecase # => "John Mark McMillan" 

资源

编辑 (受锡人的建议启发)

黑客将是:

 class String def titlecase gsub(/(?:_|\b)(.)/){$1.upcase} end end p "john mark McMillan".titlecase # => "John Mark McMillan" 

请注意,字符串'john mark McMillan'在大小写中不一致,并且作为人类输入有点意外,或者如果它不是来自人类输入,您可能不应该以这种方式存储字符串。 像'john mark mc_millan'这样'john mark mc_millan'字符串更加一致,如果你定义这样的约定,它更有可能作为人类输入出现。 我的答案也将处理这些案件:

 p "john mark mc_millan".titlecase # => "John Mark McMillan" 

titlecase的文档说([强调添加]):

将所有单词大写并替换字符串中的某些字符以创建更好看的标题。 titleize用于创建漂亮的输出。 它不用于Rails内部。

我只是在这里猜测,但也许它认为PascalCase是一个问题 – 也许它认为它是ActiveRecordModelClass的名称。

您正在尝试使用通用方法将Rail的内部字符串转换为更易读的名称。 它不是为处理“Mc”,“Mac”和“Van Der”以及任何其他复合拼写而设计的。

您可以将它作为一个起点,然后是特殊情况,结果寻找它破坏的地方并做一些修复,或者你可以编写自己的方法,包括特殊的套管那些边缘情况。 多年来,我不得不在不同的应用程序中多次这样做。

您可能还会遇到两个大写字母的名字,例如麦克拉伦,麦当劳等。

没有花时间去改进它,但你可以随时做

 # Rails.root/config/initializers/string.rb class String def titleize_name self.split(" ") .collect{|word| word[0] = word[0].upcase; word} .join(" ").gsub(/\b('?[az])/) { $1.capitalize } end end 

例子

 [2] pry(main)> "test name".titleize_name => "Test Name" [3] pry(main)> "test name-name".titleize_name => "Test Name-Name" [4] pry(main)> "test McName-name".titleize_name => "Test McName-Name" 

如果你想处理有人进入JOHN CAPSLOCK JOE以及其他人的情况,我将这个结合起来:

 class String def proper_titlecase if self.titleize.split.length == self.split.length self.titleize else self.split(" ").collect{|word| word[0] = word[0].upcase; word}.join(" ") end end end 

如果你想在String方法上有那种逻辑,取决于它;)