【问题标题】:How to capitalize the first letter in a String in Ruby如何在Ruby中将字符串中的第一个字母大写
【发布时间】:2011-04-13 02:24:24
【问题描述】:

upcase 方法将整个字符串大写,但我只需要将第一个字母大写。

另外,我需要支持几种流行的语言,例如德语和俄语。

我该怎么做?

【问题讨论】:

  • 请注意,某些语言对于首字母大写的含义不同。在爱尔兰语中,您会执行“i mBaile Átha Cliath”(“在都柏林”)之类的操作 - 小写“m”,大写“B”。 (如果您对爱尔兰人为什么会这样做以及为什么这样做感到好奇,请参阅en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages。)
  • 还要注意#capitalize 会将所有不是第一个字母的字母小写...这并不总是您想要的。 ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa']

标签: ruby


【解决方案1】:

这取决于您使用的 Ruby 版本:

Ruby 2.4 及更高版本:

它只是工作,因为Ruby v2.4.0 支持 Unicode 大小写映射:

"мария".capitalize #=> Мария

Ruby 2.3 及更低版本:

"maria".capitalize #=> "Maria"
"мария".capitalize #=> мария

问题是,它并没有做你想做的事,它输出мария而不是Мария

如果您使用的是 Rails,有一个简单的解决方法:

"мария".mb_chars.capitalize.to_s # requires ActiveSupport::Multibyte

否则,您必须安装 unicode gem 并像这样使用它:

require 'unicode'

Unicode::capitalize("мария") #=> Мария

Ruby 1.8:

一定要使用编码魔术注释:

#!/usr/bin/env ruby

puts "мария".capitalize

给出invalid multibyte char (US-ASCII),而:

#!/usr/bin/env ruby
#coding: utf-8

puts "мария".capitalize

正常工作,但也请参阅“Ruby 2.3 及更低版本”部分了解真正的大写。

【讨论】:

  • 请注意,"my API is great".capitalize 显然会产生My api is great,这可能是不受欢迎的行为。所以这个答案并没有真正回答这个问题,因为他只希望第一个字母变成大写字母,其他字母保持不变。
【解决方案2】:

字符串第一个单词的首字母大写

"kirk douglas".capitalize
#=> "Kirk douglas"

每个单词的首字母大写

在轨道中:

"kirk douglas".titleize
=> "Kirk Douglas"

"kirk_douglas".titleize
=> "Kirk Douglas"    

在红宝石中:

"kirk douglas".split(/ |\_|\-/).map(&:capitalize).join(" ") 
#=> "Kirk Douglas"

require 'active_support/core_ext'
"kirk douglas".titleize

【讨论】:

    【解决方案3】:

    不幸的是,机器不可能正确地大写/小写/大写。它需要太多的上下文信息才能让计算机理解。

    这就是为什么 Ruby 的 String 类只支持 ASCII 字符的大写,因为它至少 在某种程度上 是明确定义的。

    “上下文信息”是什么意思?

    例如,要正确大写i,您需要知道文本是哪种语言。例如,英语只有两个is:大写I不带点,小写i带一个点。但是土耳其语有四个is:大写I不带点,大写İ带点,小号ı不带点,小号i带点。所以,用英语'i'.upcase # => 'I' 和土耳其语'i'.upcase # => 'İ'。换句话说:由于'i'.upcase 可以返回两个不同的结果,这取决于语言,显然不可能在不知道其语言的情况下正确大写单词。

    但是 Ruby 不知道语言,它只知道编码。因此,使用 Ruby 的内置功能无法正确地将字符串大写。

    情况变得更糟:即使 了解该语言,有时也无法正确地进行大写。例如,在德语中,'Maße'.upcase # => 'MASSE'MaßeMaß 的复数形式,意思是 measurement)。但是,'Masse'.upcase # => 'MASSE'(意思是质量)。那么,'MASSE'.capitalize 是什么?换句话说:正确大写需要成熟的人工智能。

    因此,Ruby 有时不会给出错误答案,而是选择有时不给出答案根本,这就是为什么非 ASCII 字符在小写/大写/大写操作中被忽略的原因。 (当然也读取到错误的结果,但至少它很容易检查。)

    【讨论】:

    • 抱歉,你的论点站不住脚。 Ruby 选择根本不给出答案是不正确的,Ruby 总是给出答案,这通常是错误的——例如"мария".upcase 永远不应该返回 "мария",这在任何情况下都是不正确的。而且您对 AI 的需求的题外话根本不相关 - 没有什么可以阻止大写返回数组,例如 ['I', 'İ'] for 'i'.upcase,并让调用者决定哪个大写是相关的在给定的情况下。目前 Ruby 对大小写转换的处理已被破坏,仅此而已。
    • -1 因为有一个大写字母Eszett。使用一些非完全形式化的区域不能作为仅使用 AI 解决方案的证据。
    【解决方案4】:

    好吧,这样我们就知道如何只大写第一个字母,而不要管其余的字母,因为有时这就是我们想要的:

    ['NASA', 'MHz', 'sputnik'].collect do |word|
      letters = word.split('')
      letters.first.upcase!
      letters.join
    end
    
     => ["NASA", "MHz", "Sputnik"]
    

    调用capitalize 将导致["Nasa", "Mhz", "Sputnik"]

    【讨论】:

    • 谢谢你我正在寻找的东西,对于将标题转换为“句子大小写”很有用
    • word[0] = word[0].upcase
    • @大卫。不!这会更改调用 #collect 的数组中单词的值。这是一个不好的副作用。
    • 我展示了一种更简单的方法来将单词的第一个字母大写,替换该解决方案的内部 3 行,我通过使用 word 变量明确了这一点。当然,如果您有更多的话,只需将它们全部调用! ;) words.map{|word| word[0] = word[0].upcase}
    • @大卫。您的代码等于#capitalize! 而不是#capitalize。后者返回一个新的字符串,而前者修改了方法的接收者(在这种情况下,接收者是word,方法是#[])。如果您在 #collect 块内使用您的代码,那么您最终会得到两个不同的数组,每个数组中都有相同的 String 对象(并且字符串会被修改)。这不是你通常想做的事情。即使您知道这一点,其他读者也应该理解这一点。
    【解决方案5】:

    导轨 5+

    从 Active Support 和 Rails 5.0.0.beta4 开始,您可以使用以下两种方法之一:String#upcase_firstActiveSupport::Inflector#upcase_first

    "my API is great".upcase_first #=> "My API is great"
    "мария".upcase_first           #=> "Мария"
    "мария".upcase_first           #=> "Мария"
    "NASA".upcase_first            #=> "NASA"
    "MHz".upcase_first             #=> "MHz"
    "sputnik".upcase_first         #=> "Sputnik"
    

    查看“Rails 5: New upcase_first Method”了解更多信息。

    【讨论】:

      【解决方案6】:

      使用capitalize。来自String 文档:

      返回 str 的副本,其中第一个字符转换为大写,其余字符转换为小写。

      "hello".capitalize    #=> "Hello"
      "HELLO".capitalize    #=> "Hello"
      "123ABC".capitalize   #=> "123abc"
      

      【讨论】:

      • 如果要更改原始字符串,请仅使用感叹号。
      • doh 谢谢,修正了我的错误。
      • -1。 OP 明确 提到德语和俄语文本,这意味着非 ASCII 字符。 String#upcase(以及 String#downcase)仅针对 ASCII 字符定义。
      • 今天使用 Ruby 2.5.0 和 String#upcase 似乎在非 ASCII 字符上工作正常。 2.5.0 :001 > "мария".upcase => "МАРИЯ"
      • @Huliax 正如接受的答案中提到的那样,自 Ruby 2.4.0(2016 年发布)以来就是这种情况。
      【解决方案7】:

      我的版本:

      class String
          def upcase_first
              return self if empty?
              dup.tap {|s| s[0] = s[0].upcase }
          end
          def upcase_first!
              replace upcase_first
          end
      end
      
      ['NASA title', 'MHz', 'sputnik'].map &:upcase_first  #=> ["NASA title", "MHz", "Sputnik"]
      

      另请查看:
      https://www.rubydoc.info/gems/activesupport/5.0.0.1/String%3Aupcase_first
      https://www.rubydoc.info/gems/activesupport/5.0.0.1/ActiveSupport/Inflector#upcase_first-instance_method

      【讨论】:

        【解决方案8】:

        您可以使用mb_chars。这尊重变音符号:

        class String
        
          # Only capitalize first letter of a string
          def capitalize_first
            self[0] = self[0].mb_chars.upcase
            self
          end
        
        end
        

        示例:

        "ümlaute".capitalize_first
        #=> "Ümlaute"
        

        【讨论】:

          【解决方案9】:

          下面是另一种将字符串中的每个单词大写的方法。 \w 不匹配带有变音符号的西里尔字符或拉丁字符,但 [[:word:]] 匹配。 upcasedowncasecapitalizeswapcase 直到 2016 年发布的 Ruby 2.4.0 才适用于非 ASCII 字符。

          "aAa-BBB ä мария _a a_a".gsub(/\w+/,&:capitalize)
          => "Aaa-Bbb ä мария _a A_a"
          "aAa-BBB ä мария _a a_a".gsub(/[[:word:]]+/,&:capitalize)
          => "Aaa-Bbb Ä Мария _a A_a"
          

          [[:word:]] 匹配以下类别中的字符:

          Ll (Letter, Lowercase)
          Lu (Letter, Uppercase)
          Lt (Letter, Titlecase)
          Lo (Letter, Other)
          Lm (Letter, Modifier)
          Nd (Number, Decimal Digit)
          Pc (Punctuation, Connector)
          

          [[:word:]] 匹配“标点符号,连接符”(Pc) 类别中的所有 10 个字符:

          005F _ LOW LINE
          203F ‿ UNDERTIE
          2040 ⁀ CHARACTER TIE
          2054 ⁔ INVERTED UNDERTIE
          FE33 ︳ PRESENTATION FORM FOR VERTICAL LOW LINE
          FE34 ︴ PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
          FE4D ﹍ DASHED LOW LINE
          FE4E ﹎ CENTRELINE LOW LINE
          FE4F ﹏ WAVY LOW LINE
          FF3F _ FULLWIDTH LOW LINE
          

          这是另一种只将字符串的第一个字符转换为大写的方法:

          "striNG".sub(/./,&:upcase)
          => "StriNG"
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-01-09
            • 1970-01-01
            • 2015-06-20
            • 1970-01-01
            • 1970-01-01
            • 2014-11-26
            • 2015-07-24
            • 1970-01-01
            相关资源
            最近更新 更多