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

时间:2011-04-11 00:10:55

标签: ruby-on-rails ruby

为什么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名称的情况下,它会失败。任何想法如何解决这个问题?

10 个答案:

答案 0 :(得分:15)

如果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 

答案 1 :(得分:3)

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

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"

答案 2 :(得分:3)

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

class String
    def custom_titlecase
        self.gsub(/\b\w/) { |w| w.upcase }
    end
end

"John Mark McMillan".custom_titlecase    # => "John Mark McMillan"

Source

答案 3 :(得分:2)

已编辑(灵感来自The Tin Man的建议)

黑客将是:

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'的字符串更加一致,如果您定义此类约定,则更有可能显示为人工输入。我的回答也将处理这些案例:

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

答案 4 :(得分:1)

标题词的documentation表示([强调添加]):

  

将所有单词 大写并替换   字符串 中的一些字符   创造一个更好看的标题。 titleize   用于创建漂亮的输出。   它没有在Rails内部使用。

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

答案 5 :(得分:1)

如果你想处理有人输入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方法的那种逻辑;)

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

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

没有花时间尝试改进它,但你总能做到

<强>代码

# Rails.root/config/initializers/string.rb
class String
  def titleize_name
    self.split(" ")
      .collect{|word| word[0] = word[0].upcase; word}
      .join(" ").gsub(/\b('?[a-z])/) { $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"

答案 8 :(得分:0)

我们刚刚添加了此功能,它支持我们面临的几种不同情况。

class String
  # Default titlecase converts McKay to Mc Kay, which is not great
  # May even need to remove titlecase completely in the future to leave 
  # strings unchanged
  def self.custom_title_case(string = "")
    return "" if !string.is_a?(String) || string.empty?

    split = string.split(" ").collect do |word|
      word = word.titlecase

      # If we titlecase and it turns in to 2 words, then we need to merge back
      word = word.match?(/\w/) ? word.split(" ").join("") : word
      
      word
    end
    
    return split.join(" ")
  end
end

和rspec测试

# spec/lib/modules/string_spec.rb
require 'rails_helper'
require 'modules/string'

describe "String" do
  describe "self.custom_title_case" do
    it "returns empty string if incorrect params" do
      result_one = String.custom_title_case({ test: 'object' })
      result_two = String.custom_title_case([1, 2])
      result_three = String.custom_title_case()

      expect(result_one).to eq("")
      expect(result_two).to eq("")
      expect(result_three).to eq("")
    end

    it "returns string in title case" do
      result = String.custom_title_case("smiths hill")
      expect(result).to eq("Smiths Hill")
    end

    it "caters for 'Mc' i.e. 'john mark McMillan' edge cases" do
      result_one = String.custom_title_case("burger king McDonalds")
      result_two = String.custom_title_case("john mark McMillan")
      result_three = String.custom_title_case("McKay bay")

      expect(result_one).to eq("Burger King McDonalds")
      expect(result_two).to eq("John Mark McMillan")
      expect(result_three).to eq("McKay Bay")
    end

    it "correctly cases uppercase words" do
      result = String.custom_title_case("NORTH NARRABEEN")
      expect(result).to eq("North Narrabeen")
    end
  end
end

答案 9 :(得分:-1)

“为什么”问题已经answered ...但是,正如所选答案和支持所证明的那样,我认为我们大多数人实际上想要的是解决地狱这一难题的灵丹妙药-formatting ...虽然有多个大写字母触发了该行为,但我发现带连字符的名称也是如此。

这些案例以及更多案例已经在 NameCase 宝石中处理过。

在2.0版中,仅当字符串全部为大写或全部为小写时,才根据定义的规则集转换字符串。我喜欢这个,因为我敢肯定规则集永远不可能是100%正确的。例如, Ian McDonald(来自苏格兰)的大写字母与Ian Mcdonald(来自爱尔兰) 的字母大写不同...但是,如果输入了正确的名称,这些名称将在输入时正确处理用户是特定用户,如果不是,则可以根据需要更正名称并保留其格式。

我的解决方案:

# If desired, add string method once NameCase gem is added
class String

  def namecase
    NameCase(self)
  end

end

测试:(name.namecase)

test_names = ["john mark McMillan", "JOHN CAPSLOCK JOE", "test name", "test name-name", "test McName-name", "John w McHENRY", "ian mcdonald", "Ian McDonald", "Ian Mcdonald"]

test_names.each { |name| puts '# "' + name + '" => "' + name.namecase + '"' }
  # "john mark McMillan" => "John Mark McMillan"
  # "JOHN CAPSLOCK JOE" => "John Capslock Joe"
  # "test name" => "Test Name"
  # "test name-name" => "Test Name-Name"
  # "test McName-name" => "Test McName-Name"
  # "John w McHENRY" => "John w McHENRY" -FAIL
  # "ian mcdonald" => "Ian McDonald"
  # "Ian McDonald" => "Ian McDonald"
  # "Ian Mcdonald" => "Ian Mcdonald"

如果您认为需要处理此页面上的所有特殊情况,并且不必担心丢失开头可能已经格式化的名称,例如。 Ian Mcdonald(来自爱尔兰) ...您可以先使用upcase

测试:(name.upcase.namecase)

test_names.each { |name| puts '# "' + name + '" => "' + name.upcase.namecase + '"' }
  # "john mark McMillan" => "John Mark McMillan"
  # "JOHN CAPSLOCK JOE" => "John Capslock Joe"
  # "test name" => "Test Name"
  # "test name-name" => "Test Name-Name"
  # "test McName-name" => "Test McName-Name"
  # "John w McHENRY" => "John W McHenry"
  # "ian mcdonald" => "Ian McDonald"
  # "Ian McDonald" => "Ian McDonald"
  # "Ian Mcdonald" => "Ian McDonald"

唯一的灵丹妙药就是去上学...全部成功。但是谁愿意在他们的现代网络应用程序中看到这种眼神呢?