¿Poner en mayúscula solo el primer carácter de la cadena y dejar en paz a los demás? (Rieles)

102

Estoy tratando de que Rails ponga en mayúscula el primer carácter de una cadena y deje todos los demás como están. Me encuentro con un problema en el que "soy de Nueva York" se convierte en "Soy de Nueva York".

¿Qué método usaría para seleccionar el primer carácter?

Gracias

EDITAR: Traté de implementar lo que sugirió macek, pero obtengo un error de "método indefinido 'capitalizar'" . El código funciona bien sin la línea en mayúscula. ¡Gracias por la ayuda!

def fixlistname!
  self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...")
  self.title[0] = self.title[0].capitalize
  errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with? 'You know you'
end

EDITAR 2: Lo tengo funcionando. ¡Gracias por la ayuda!

EDITAR 3: Espera, no, no lo hice ... Esto es lo que tengo en mi modelo de lista.

def fixlistname!
  self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...")
  self.title.slice(0,1).capitalize + self.title.slice(1..-1)
  errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with?  'You know you'
end

EDITAR 4: Probé la edición de macek, y aún obtengo un error de método indefinido "capitalizar" . ¿Qué podría estar haciendo mal?

def fixlistname!
  self.title = title.lstrip
  self.title += '...' unless title.ends_with?('...')
  self.title[0] = title[0].capitalize
  errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you")
end

EDITAR 5: Esto es extraño. Puedo deshacerme del error del método indefinido usando la línea a continuación. El problema es que parece reemplazar la primera letra con un número. Por ejemplo, en lugar de poner en mayúscula la y en usted , convierte la y en un 121

self.title[0] = title[0].to_s.capitalize
Daniel O'Connor
fuente
Basado en EDIT 3, debe comenzar la línea 2 con self.title = . Además, en las 3 líneas, solo necesita self.titlea la izquierda de un =(signo igual). En otros lugares puedes usar title. Vea la edición de mi respuesta para ver un ejemplo.
maček
2
El problema en Edit4 es que solo tiene un carácter, ya no una cadena, por lo tanto, no reconocerá la función de cadena "capitalizar".
Taryn East
El problema con la Edición 5 es que el título [0] es un número fijo, por lo que llamar al título [0] .to_s solo le dará el número de carácter (es decir, 121 como una cadena: "121"). ¡Puedes hacer self.title [0] = title.first.capitalize si quieres!
Nick
Agregué un #upcase_first_case e hice una solicitud de extracción: github.com/rails/rails/pull/15319 . No dude en agregar sus comentarios allí.
Aldo 'xoen' Giambelluca

Respuestas:

93

Titleize pondrá en mayúscula cada palabra. Esta línea se siente pesada, pero garantizará que la única letra cambiada sea la primera.

new_string = string.slice(0,1).capitalize + string.slice(1..-1)

Actualizar:

irb(main):001:0> string = "i'm from New York..."
=> "i'm from New York..."
irb(main):002:0> new_string = string.slice(0,1).capitalize + string.slice(1..-1)
=> "I'm from New York..."
Taryn East
fuente
Espera, todavía no funciona. Falsa alarma: / Creo que lo estoy implementando mal.
Daniel O'Connor
1
Daniel: por lo general, es una buena forma "aceptar" una respuesta que resolvió tu problema. Puede hacer esto haciendo clic en la "marca" a la izquierda de la respuesta. :)
Taryn East
1
Entendí mal la pregunta, de lo contrario, quería darle un 1. Estaba buscando .titleize en lugar de .capitalize. ¡Gracias de todos modos Taryn!
Eric Wanchic
OOC - ¿Por qué eso le impide dar un voto a favor? ¿Respondí correctamente a la pregunta del póster original? Si lo cree, entonces vote a favor. No tiene que depender de nada más ... :)
Taryn East
2
Entonces, aquí va: s[0].capitalize + s[1..-1] if s.present?
Alex Escalante
126

Esto debería hacerlo:

title = "test test"     
title[0] = title[0].capitalize
puts title # "Test test"
Pascal Van Hecke
fuente
40
O más concisamente,title[0] = title[0].capitalize
Jon Garvin
Esta es una solución muy elegante.
Karew
1
@JonGarvin title [0] .capitalize no funciona (al menos con Ruby 1.8.7), ya que title [0] devuelve un Fixnum, y capitalize espera una cadena .. así que creo que title.first.capitalize es la forma de Vamos.
Nick
2
lástima que no puedastitle.first.capitalize!
Adam Waite
1
capitalizeconvierte todas las letras después de la primera letra a minúsculas, por lo que no funciona para la cadena presentada en la pregunta ("soy de Nueva York").
Mark Schneider
57

Puedes usar humanizar. Si no necesita guiones bajos u otras mayúsculas en sus líneas de texto.

Entrada:

"i'm from New_York...".humanize

Salida:

"I'm from new york..."
Bartuzz
fuente
7
El OP quería específicamente evitar 'Nueva York'
phatmann
De hecho, un poco demasiado rápido con mi respuesta.
Bartuzz
17
@Bartuzz Aunque esto no es lo que OP quería, esto es exactamente lo que estaba buscando. ¡Gracias!
Yetti
new york, sin embargo, no sería gramatical como nombre propio y debería usar mayúsculas.
Shayne
Tenga humanizecuidado , es el método Rails, exactamente ActiveSupport. El rubí simple no puede hacer eso.
Penguin
51
str = "this is a Test"
str.sub(/^./, &:upcase)
# => "This is a Test"
Litera Lasse
fuente
1
Conciso y elegante. Creo que esta debería ser la mejor respuesta.
Chris
Estoy de acuerdo. Creo que esta debería ser la respuesta aceptada.
Garry Pettet
Una peculiaridad es que desde ^significa principio de línea, se "\nfoo"convierte en "\nFoo". Probablemente eso esté bien para la mayoría de los casos de uso. Dado que es a suby no a gsub, solo subirá una letra, incluso con cadenas de varias líneas.
Henrik N
Puede obtener la limitación anterior usando str.sub(/\S/, &:upcase), que buscará el primer carácter que no sea un espacio en blanco y lo reemplazará.
Anthony Panozzo
39

A partir de Rails 5.0.0.beta4 puedes usar el nuevo String#upcase_firstmétodo o ActiveSupport::Inflector#upcase_firsthacerlo. Consulte esta publicación de blog para obtener más información.

usuario1519240
fuente
¡Esas son buenas noticias! Estaba pensando en lo que podemos hacer ahora y tal vez un polyfill para Rails 4 sería bueno.
hakunin
Tenga en cuenta que upcase_first y no maneja acentos / caracteres especiales, incluso con mb_chars
user3033467
14

Una solución orientada a objetos:

class String
  def capitalize_first_char
    self.sub(/^(.)/) { $1.capitalize }
  end
end

Entonces puedes hacer esto:

"i'm from New York".capitalize_first_char
modales
fuente
Al menos alguien escribió una solución elegante con extensión de Stringclase.
Dmitriy
@Dmitriy ¿por qué el mono parcheando la clase de cadena es elegante?
Gerard Simpson
7
str.sub(/./, &:capitalize)
emlai
fuente
6

Editar 2

Parece que no puedo replicar tu problema. Continúe y ejecute este script nativo de Ruby. Genera la salida exacta que estás buscando y Rails admite todos estos métodos. ¿Con qué tipo de entradas tiene problemas?

#!/usr/bin/ruby
def fixlistname(title)
  title = title.lstrip
  title += '...' unless title =~ /\.{3}$/
  title[0] = title[0].capitalize
  raise 'Title must start with "You know you..."' unless title =~ /^You know you/
  title
end

DATA.each do |title|
  puts fixlistname(title)
end

__END__
you know you something WITH dots ...
you know you something WITHOUT the dots
  you know you something with LEADING whitespace...
  you know you something with whitespace BUT NO DOTS
this generates error because it doesn't start with you know you

salida

You know you something WITH dots ...
You know you something WITHOUT the dots...
You know you something with LEADING whitespace...
You know you something with whitespace BUT NO DOTS...
RuntimeError: Title must start with "You know you..."

Editar

Según tu edición, puedes probar algo como esto.

def fixlistname!
  self.title = title.lstrip
  self.title += '...' unless title.ends_with?('...')
  self.title[0] = title[0].capitalize
  errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you")
end

Original

Esto hará el truco

s = "i'm from New York"
s[0] = s[0].capitalize
#=> I'm from New York

Al intentar usar String#capitalizeen toda la cadena, estaba viendo I'm from new yorkporque el método:

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

"hello".capitalize    #=> "Hello"
"HELLO".capitalize    #=> "Hello"
"123ABC".capitalize   #=> "123abc"
maček
fuente
+1 porque no pensé que funcionaría hasta que lo probé en mi PC :)
Jeriko
Hola, gracias por la ayuda. ¿Qué estoy haciendo mal? Edité la pregunta original para incluir mi código.
Daniel O'Connor
Usé la sugerencia de Taryn y la hice funcionar. ¡Gracias por la ayuda!
Daniel O'Connor
Hola, stackoverflow dice que hiciste una edición, pero no veo nada diferente.
Daniel O'Connor
6
my_string = "hello, World"
my_string.sub(/\S/, &:upcase) # => "Hello, World"
Pavel Pravosud
fuente
¡No falla si my_string está vacío! Agradable. Esto es lo que necesito.
Huliax
4

La mayoría de estas respuestas editan la cadena en su lugar, cuando solo está formateando para la salida de la vista, es posible que no desee cambiar la cadena subyacente para que pueda usar tapdespués de duppara obtener una copia editada

'test'.dup.tap { |string| string[0] = string[0].upcase }
Paul.s
fuente
3

Si y solo si OP quisiera hacer un parche de mono en el objeto String, entonces esto se puede usar

class String
  # Only capitalize first letter of a string
  def capitalize_first
    self.sub(/\S/, &:upcase)
  end
end

Ahora úsalo:

"i live in New York".capitalize_first #=> I live in New York
JVK
fuente
2

Una versión aún más corta podría ser:

s = "i'm from New York..."
s[0] = s.capitalize[0]
Saim
fuente
2

Nadie ha mencionado gsub, lo que le permite hacer esto de forma concisa.

string.gsub(/^([a-z])/) { $1.capitalize }

Ejemplo:

 > 'caps lock must go'.gsub(/^(.)/) { $1.capitalize }
=> "Caps lock must go"
mahemoff
fuente
1

Quizás la forma más sencilla.

s = "test string"
s[0] = s[0].upcase
# => "Test string"
Lukas Baliak
fuente
0

¿Qué pasa con el método de clasificación en cadena?

'somESTRIng'.classify

salida:

#rails => 'SomESTRIng'
mArtinko5MB
fuente
1
Está haciendo muchas cosas adicionales, como singularizar palabras. "hello worlds".classify # => "Hello world"
Pavel Pravosud
-3
string = "i'm from New York"
string.split(/\s+/).each{ |word,i| word.capitalize! unless i > 0 }.join(' ')
# => I'm from New York
Jeriko
fuente
Parece tan. Soy nuevo en ruby, y las otras respuestas en realidad no hicieron lo que pidió el OP, así que lo hice funcionar: D Corríjame si me equivoco, pero AFAIK modificar una cadena cambiando la cadena [i] no trabaja en muchos idiomas?
Jeriko
3
esta es una pregunta específica de Ruby. No importa si string[i]no funciona en otros idiomas. Por favor, ayude a mantener StackOverflow libre de este tipo de respuestas pirateadas. No podemos decir RTFM, pero incluso un vistazo rápido a los Stringdocumentos habría ayudado a evitar una respuesta como esta ...
maček