Почему заголовок Rails добавляет пробел в имя?

Почему 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 это терпит неудачу. Любые идеи, как это исправить?

Ответ 1

Вы всегда можете сделать это самостоятельно, если 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 

Ответ 2

Если вы хотите, чтобы каждое слово начиналось с капитала:

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"

Ответ 3

Хм, это странно.. но вы могли бы написать быстрое пользовательское регулярное выражение, чтобы избежать использования этого метода.

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

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

Источник

Ответ 4

Отредактировано (вдохновлено предложением 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"

Ответ 5

документация для заголовка темы ([выделено мной]]:

Заглавные буквы всех слов и заменяет некоторые символы в строке до создайте красиво выглядящий заголовок. titleize предназначен для создания довольно вывода. Он не используется во внутренних компонентах Rails.

Я только угадываю здесь, но, возможно, это относится к PascalCase как к проблеме - возможно, он думает, что это имя ActiveRecordModelClass.

Ответ 6

Вы пытаетесь использовать общий метод преобразования внутренних строк Rail в более понятные для человека имена. Он не предназначен для обработки "Mc" и "Mac" и "Van Der" и любого количества других сложных написаний.

Вы можете использовать его в качестве отправной точки, а затем в специальном случае результаты поиска мест, которые он разбивает, и делать некоторые исправления, или вы можете написать свой собственный метод, который включает в себя специальные обложки этих крайних случаев. Мне приходилось делать это несколько раз в разных приложениях на протяжении многих лет.

Ответ 7

Вы также можете столкнуться с именами с двумя прописными буквами, такими как McLaren, McDonald и т.д.

Не тратили время на его улучшение, но вы всегда могли

код

# 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

Если вы хотите обработать случай, когда кто-то ввел 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;)