Como colocar em maiúscula a primeira letra em uma String em Ruby


134

O upcasemétodo coloca em maiúscula a string inteira, mas eu preciso colocar em maiúscula apenas a primeira letra.

Além disso, preciso oferecer suporte a vários idiomas populares, como alemão e russo.

Como eu faço isso?


4
Esteja ciente de que alguns idiomas têm idéias diferentes sobre qual é a primeira letra a ser maiúscula. Em irlandês, você faz coisas como "i mBaile Átha Cliath" ("em Dublin") - minúsculo 'm', maiúsculo 'B'. (Ver en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages Se você está curioso sobre o porquê irlandesa faria isso e por que faz sentido.)
James Moore

3
E lembre-se de que #capitalize reduzirá todas as letras que não forem a primeira letra ... que nem sempre é o que você deseja. ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa']
Huliax 9/11/2015

Respostas:


260

Depende da versão do Ruby que você usa:

Ruby 2.4 e superior:

Apenas funciona, já que o Ruby v2.4.0 suporta o mapeamento de casos Unicode:

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

Ruby 2.3 e inferior:

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

O problema é que ele simplesmente não faz o que você quer, ele produz em марияvez de Мария.

Se você estiver usando o Rails, há uma solução fácil:

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

Caso contrário, você precisará instalar a gem unicode e usá-la da seguinte maneira:

require 'unicode'

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

Ruby 1.8:

Certifique-se de usar o comentário mágico de codificação :

#!/usr/bin/env ruby

puts "мария".capitalize

invalid multibyte char (US-ASCII), enquanto:

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

puts "мария".capitalize

funciona sem erros, mas também consulte a seção "Ruby 2.3 e inferior" para capitalização real.


19
Observe que, aparentemente "my API is great".capitalize, produzirá o My api is greatque provavelmente é um comportamento indesejado. Portanto, essa resposta realmente não responde à pergunta, pois ele só quer que a PRIMEIRA letra seja maiúscula e outras intocadas.
Daniel AR Werner

55

colocar em maiúscula a primeira letra da primeira palavra da sequência

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

colocar em maiúscula a primeira letra de cada palavra

Nos trilhos:

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

OU

"kirk_douglas".titleize
=> "Kirk Douglas"    

Em rubi:

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

fora dos trilhos, mas ainda quer usar o método titleize

require 'active_support/core_ext'
"kirk douglas".titleize #or capitalize

1
Voto positivo para uma solução Ruby pura. Com preguiça de fogo até Rails adequada, e este fez o truque :)
illbzo1

19

Infelizmente, é impossível que uma máquina faça upcase / downcase / capitalize corretamente. Ele precisa de muita informação contextual para um computador entender.

É por isso que a Stringclasse Ruby suporta apenas letras maiúsculas para caracteres ASCII, porque é pelo menos um pouco bem definida.

O que quero dizer com "informação contextual"?

Por exemplo, para capitalizar icorretamente, é necessário saber em qual idioma o texto está. O inglês, por exemplo, possui apenas dois is: capital Isem ponto e pequeno icom ponto. Mas o turco tem quatro is: capital Isem ponto, capital İcom ponto, pequeno ısem ponto, pequeno icom ponto. Então, em inglês 'i'.upcase # => 'I'e em turco 'i'.upcase # => 'İ'. Em outras palavras: como 'i'.upcasepode retornar dois resultados diferentes, dependendo do idioma, é obviamente impossível capitalizar corretamente uma palavra sem conhecer seu idioma.

Mas Ruby não conhece o idioma, apenas conhece a codificação. Portanto, é impossível capitalizar adequadamente uma string com a funcionalidade interna do Ruby.

Piora: mesmo com o conhecimento do idioma, às vezes é impossível fazer uma capitalização adequada. Por exemplo, em alemão 'Maße'.upcase # => 'MASSE'( Maße é o plural de Maß que significa medição ). No entanto, 'Masse'.upcase # => 'MASSE'(significando massa ). Então o que é 'MASSE'.capitalize? Em outras palavras: capitalizar corretamente requer uma Inteligência Artificial completa.

Assim, em vez de às vezes dando a resposta errada, Ruby opta por vezes, dar nenhuma resposta em tudo , e é por isso caracteres não-ASCII simplesmente ignorados em downcase / upcase / capitalizar operações. (O que, é claro, também indica resultados errados, mas pelo menos é fácil verificar.)


4
Desculpe, mas sua argumentação não retém a água. Não é verdade que Ruby opte por não dar uma resposta, Ruby sempre dá uma resposta, o que geralmente está errado - por exemplo, "мария" .upcase nunca deve retornar "мария", que não é correto em nenhum contexto. E suas digressões sobre a necessidade de IA não são relevantes - não há nada que impeça a retenção de uma matriz em caixa alta, diga ['I', 'İ'] para 'i'.upcase e deixe o chamador decidir qual capitalização é relevante em uma determinada situação. Atualmente, o processamento da conversão do Ruby entre maiúsculas e minúsculas está quebrado, e é isso.
Michau

2
-1 porque existe uma capital Eszett . O uso de alguma área não completamente formalizada não pode servir como prova dessa solução apenas com IA.
Mike

15

Bem, só para saber como colocar em maiúscula apenas a primeira letra e deixar o resto em paz, porque às vezes é isso que se deseja:

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

 => ["NASA", "MHz", "Sputnik"]

A chamada capitalizeresultaria em ["Nasa", "Mhz", "Sputnik"].


Obrigado exatamente o que eu estava procurando, útil para converter títulos para 'caso frase'
Boa Lux

2
word[0] = word[0].upcase
David

@David. NÃO! Isso altera os valores das palavras na matriz em que #collect é chamado. Esse é um efeito colateral ruim.
Huliax 14/05/19

Eu estava mostrando uma maneira mais simples de colocar em maiúscula a primeira letra de uma palavra, substituindo as três linhas internas desta solução, que deixei claro usando a wordvariável Claro, se você tiver mais palavras, basta chamá-las de todas! ;)words.map{|word| word[0] = word[0].upcase}
David

@David. Seu código equivale a #capitalize!e não #capitalize. O último retorna uma nova String enquanto o primeiro modifica o receptor do método (nesse caso, o receptor é worde o método é #[]). Se você usasse seu código dentro de um bloco #collect, acabaria com duas matrizes diferentes com os mesmos objetos String em cada um deles (e as Strings teriam sido modificadas). Isso não é algo que você normalmente gostaria de fazer. Mesmo se você estiver ciente disso, outros leitores devem entender isso.
Huliax 15/05/19

8

Rails 5+

No Active Support and Rails 5.0.0.beta4, você pode usar um dos dois métodos: String#upcase_firstou ActiveSupport::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"

Verifique " Rails 5: Novo método upcase_first " para obter mais informações.


3

Use capitalize. Na documentação da String :

Retorna uma cópia de str com o primeiro caractere convertido em maiúsculas e o restante em minúsculas.

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

Use o ponto de exclamação apenas se desejar que a string original seja alterada.
Magnar

doh Obrigado, corrigi meu erro.
jhwist

5
-1. O OP menciona explicitamente texto em alemão e russo, o que implica caracteres não ASCII. String#upcase(e também String#downcase) são definidos apenas para caracteres ASCII.
Jörg W Mittag

1
Usando o Ruby 2.5.0 hoje e String#upcaseparece funcionar bem em caracteres não ASCII. 2.5.0 :001 > "мария".upcase => "МАРИЯ"
Huliax

1
@Huliax Conforme mencionado na resposta aceita, esse só ocorreu desde o Ruby 2.4.0 (lançado em 2016).
Nisetama

2

Você pode usar mb_chars. Isso respeita o trema:

class String

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

end

Exemplo:

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

0

Abaixo está outra maneira de colocar em maiúscula cada palavra em uma sequência. \wnão combina caracteres cirílicos ou caracteres latinos com sinais diacríticos, mas [[:word:]]sim. upcase, downcase, capitalize, E swapcasenão se aplica a caracteres não-ASCII até o Ruby 2.4.0, que foi lançado em 2016.

"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:]] corresponde a caracteres nestas categorias:

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

[[:word:]]corresponde a todos os 10 caracteres na categoria "Pontuação, conector" ( Pc):

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

Essa é outra maneira de converter apenas o primeiro caractere de uma string em maiúsculas:

"striNG".sub(/./,&:upcase)
=> "StriNG"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.