Why does Rails titlecase add a space to a name?

前端 未结 10 1166
我在风中等你
我在风中等你 2021-02-05 10:28

Why does the titlecase mess up the name? I have:

John Mark McMillan

and it turns it into:

>> \"john mark McM         


        
相关标签:
10条回答
  • 2021-02-05 10:36

    You may also encounter names with two capital letters, such as McLaren, McDonald etc.

    Have not spent time trying to improve it, but you could always do

    Code

    # 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
    

    Examples

    [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"
    
    0 讨论(0)
  • 2021-02-05 10:37

    Edited (inspired by The Tin Man's suggestion)

    A hack will be:

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

    Note that the string 'john mark McMillan' is inconsistent in capitalization, and is somewhat unexpected as a human input, or if it is not from a human input, you probably should not have the strings stored in that way. A string like 'john mark mc_millan' is more consistent, and would more likely appear as a human input if you define such convention. My answer will handle these cases as well:

    p "john mark mc_millan".titlecase
    # => "John Mark McMillan"
    
    0 讨论(0)
  • 2021-02-05 10:38

    The documentation for titlecase says ([emphasis added]):

    Capitalizes all the words and replaces some characters in the string to create a nicer looking title. titleize is meant for creating pretty output. It is not used in the Rails internals.

    I'm only guessing here, but perhaps it regards PascalCase as a problem - maybe it thinks it's the name of a ActiveRecordModelClass.

    0 讨论(0)
  • 2021-02-05 10:45

    Hmm, that's odd.. but you could write a quick custom regex to avoid using that method.

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

    Source

    0 讨论(0)
  • 2021-02-05 10:45

    We have just added this which supports a few different cases that we face.

    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
    
    

    And the rspec test

    # 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
    
    0 讨论(0)
  • 2021-02-05 10:46

    If all you want is to ensure that each word starts with a capital:

    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"
    
    0 讨论(0)
提交回复
热议问题