Cómo poner en mayúscula la primera letra de una Cadena en Ruby

134

El upcasemétodo capitaliza toda la cadena, pero necesito capitalizar solo la primera letra.

Además, necesito admitir varios idiomas populares, como el alemán y el ruso.

¿Cómo lo hago?

AntonAL
fuente
44
Tenga en cuenta que algunos idiomas tienen ideas diferentes sobre cuál es la primera letra en mayúscula. En irlandés, haces cosas como "i mBaile Átha Cliath" ("en Dublín"): minúscula 'm', mayúscula 'B'. (Vea en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages si tiene curiosidad acerca de por qué los irlandeses harían eso y por qué tiene sentido).
James Moore
3
Y también tenga en cuenta que #capitalize reducirá todas las letras que no sean la primera letra ... que no siempre es lo que desea. ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa']
Huliax

Respuestas:

260

Depende de la versión de Ruby que uses:

Ruby 2.4 y superior:

Simplemente funciona, ya que Ruby v2.4.0 admite la asignación de casos Unicode:

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

Ruby 2.3 y más bajo:

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

El problema es que simplemente no hace lo que quieres que haga, emite en марияlugar de Мария.

Si está utilizando Rails, hay una solución fácil:

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

De lo contrario, tendrá que instalar la gema Unicode y usarla así:

require 'unicode'

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

Ruby 1.8:

Asegúrese de usar el comentario mágico de codificación :

#!/usr/bin/env ruby

puts "мария".capitalize

da invalid multibyte char (US-ASCII), mientras que:

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

puts "мария".capitalize

funciona sin errores, pero también vea la sección "Ruby 2.3 y versiones inferiores" para la capitalización real.

Alberto Santini
fuente
19
Tenga en cuenta que aparentemente "my API is great".capitalizeproducirá lo My api is greatque probablemente sea un comportamiento no deseado. Por lo tanto, esta respuesta realmente no responde a la pregunta, ya que solo quiere que la PRIMERA carta se convierta en mayúsculas y otras no se toquen.
Daniel AR Werner
55

escribe con mayúscula la primera letra de la primera palabra de la cadena

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

escribe con mayúscula la primera letra de cada palabra

En rieles:

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

O

"kirk_douglas".titleize
=> "Kirk Douglas"    

En rubí:

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

fuera de los rieles, pero aún desea utilizar el método de título

require 'active_support/core_ext'
"kirk douglas".titleize #or capitalize
boulder_ruby
fuente
1
Vota a favor de una solución de Ruby pura. Demasiado perezoso para encender Rails, y esto funcionó :)
illbzo1
19

Desafortunadamente, es imposible que una máquina aumente / reduzca / capitalice correctamente. Necesita demasiada información contextual para que una computadora la entienda.

Es por eso que la Stringclase de Ruby solo admite mayúsculas para los caracteres ASCII, porque allí está al menos algo bien definido.

¿Qué quiero decir con "información contextual"?

Por ejemplo, para capitalizar icorrectamente, necesita saber en qué idioma está el texto. El inglés, por ejemplo, solo tiene dos is: capital Isin punto y pequeño icon punto. Pero el turco tiene cuatro is: capital Isin punto, capital İcon punto, pequeño ısin punto, pequeño icon punto. Entonces, en inglés 'i'.upcase # => 'I'y en turco 'i'.upcase # => 'İ'. En otras palabras: dado que 'i'.upcasepuede devolver dos resultados diferentes, dependiendo del idioma, es obviamente imposible poner en mayúscula correctamente una palabra sin conocer su idioma.

Pero Ruby no conoce el idioma, solo conoce la codificación. Por lo tanto, es imposible capitalizar correctamente una cadena con la funcionalidad incorporada de Ruby.

Se pone peor: incluso con el conocimiento del idioma, a veces es imposible capitalizar correctamente. Por ejemplo, en alemán, 'Maße'.upcase # => 'MASSE'( Maße es el plural de Maß que significa medición ). Sin embargo, 'Masse'.upcase # => 'MASSE'(que significa masa ). Entonces que es 'MASSE'.capitalize? En otras palabras: capitalizar correctamente requiere una Inteligencia Artificial completa.

Así, en lugar de dando a veces la respuesta equivocada, Ruby decide a veces no dan ninguna respuesta en absoluto , por lo que los caracteres no ASCII simplemente ignorados en downcase / upcase / capitalizar las operaciones. (Lo que, por supuesto, también se traduce en resultados incorrectos, pero al menos es fácil de verificar).

Jörg W Mittag
fuente
44
Lo sentimos, pero tu argumentación no aguanta. No es cierto que Ruby elija no dar una respuesta, Ruby siempre da una respuesta, que a menudo es incorrecta, por ejemplo, "мария" .upcase nunca debe devolver "мария", eso no es correcto en ningún contexto. Y sus digresiones sobre la necesidad de AI no son relevantes en absoluto: no hay nada que impida que una caja se retome, digamos ['I', 'İ'] para 'i'.upcase, y dejar que la persona que llama decida qué capitalización es relevante en una situación dada Actualmente, el manejo de la conversión de Ruby entre mayúsculas y minúsculas está roto, y eso es todo.
michau
2
-1 porque hay una capital Eszett . El uso de un área no completamente formalizada no puede servir como prueba de que la solución es posible solo con IA.
Mike
15

Bueno, para que sepamos cómo capitalizar solo la primera letra y dejar el resto solo, porque a veces eso es lo que se desea:

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

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

Llamar capitalizeresultaría en ["Nasa", "Mhz", "Sputnik"].

Huliax
fuente
Gracias por lo que estaba buscando, útil para convertir encabezados a 'caso de oración'
Good Lux
2
word[0] = word[0].upcase
David
@David. ¡NO! Eso cambia los valores de las palabras en la matriz a la que se llama #collect. Ese es un mal efecto secundario.
Huliax
Estaba mostrando una forma más simple de poner en mayúscula la primera letra de una palabra, reemplazando las 3 líneas internas de esta solución, lo que dejé en claro al usar la wordvariable. Por supuesto, si tienes más palabras, ¡solo llámalas todas! ;)words.map{|word| word[0] = word[0].upcase}
David
@David. Su código equivale a #capitalize!y no #capitalize. El último devuelve una nueva cadena mientras que el primero modifica el receptor del método (en este caso, el receptor es wordy el método es #[]). Si usó su código dentro de un bloque #collect, terminaría con dos matrices diferentes con los mismos objetos de cadena en cada uno de ellos (y las cadenas se habrían modificado). Eso no es algo que normalmente quieras hacer. Incluso si eres consciente de esto, otros lectores deberían entenderlo.
Huliax
8

Rieles 5+

A partir de Active Support y Rails 5.0.0.beta4 puede usar uno de los dos métodos: String#upcase_firsto 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"

Consulte " Rails 5: nuevo método upcase_first " para obtener más información.

usuario1519240
fuente
3

Uso capitalize. De la documentación de String :

Devuelve una copia de str con el primer carácter convertido en mayúsculas y el resto en minúsculas.

"hello".capitalize    #=> "Hello"
"HELLO".capitalize    #=> "Hello"
"123ABC".capitalize   #=> "123abc"
jhwist
fuente
Solo use el signo de exclamación si desea cambiar la cadena original.
Magnar
doh Gracias, arreglé mi error.
jhwist
55
-1. El OP menciona explícitamente texto en alemán y ruso, lo que implica caracteres no ASCII. String#upcase(y también String#downcase) solo se definen para caracteres ASCII.
Jörg W Mittag
1
Usa Ruby 2.5.0 hoy y String#upcaseparece funcionar bien en caracteres no ASCII. 2.5.0 :001 > "мария".upcase => "МАРИЯ"
Huliax
1
@Huliax Como se mencionó en la respuesta aceptada, ese solo ha sido el caso desde Ruby 2.4.0 (que se lanzó en 2016).
nisetama
2

Puedes usar mb_chars. Esto respeta la diéresis:

class String

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

end

Ejemplo:

"ümlaute".capitalize_first
#=> "Ümlaute"
phlegx
fuente
0

A continuación se muestra otra forma de capitalizar cada palabra en una cadena. \wno coincide con los caracteres cirílicos o latinos con signos diacríticos, pero [[:word:]]sí. upcase, downcase, capitalize, Y swapcaseno se aplica a los caracteres no ASCII hasta Rubí 2.4.0, que fue lanzado en 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:]] coincide con los personajes de estas categorías:

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

[[:word:]]coincide con los 10 caracteres de la categoría "Puntuación, 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

Esta es otra forma de convertir solo el primer carácter de una cadena a mayúsculas:

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