Capitalizar apenas o primeiro caractere da string e deixar os outros em paz? (Trilhos)


102

Estou tentando fazer com que o Rails coloque em maiúscula o primeiro caractere de uma string e deixe todos os outros do jeito que estão. Estou tendo um problema em que "sou de Nova York" se transforma em "Sou de Nova York".

Que método devo usar para selecionar o primeiro personagem?

obrigado

EDIT: Eu tentei implementar o que o macek sugeriu, mas estou recebendo um erro "método indefinido` capitalize '" . O código funciona bem sem a linha maiúscula. Obrigado pela ajuda!

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

EDIT 2: está funcionando. Obrigado pela ajuda!

EDIT 3: Espere, não, eu não ... Aqui está o que tenho no meu 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

EDIT 4: Tentei editar o macek e ainda estou obtendo um erro de método indefinido `capitalize '" . O que posso estar fazendo de errado?

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

EDIT 5: Isso é estranho. Consigo me livrar do erro do método indefinido usando a linha abaixo. O problema é que parece substituir a primeira letra por um número. Por exemplo, em vez de colocar y em maiúscula em Você , ele transforma y em 121

self.title[0] = title[0].to_s.capitalize

Com base em EDIT 3, você precisa iniciar a linha 2 com self.title = . Além disso, em todas as 3 linhas, você só precisa self.titleà esquerda de um =(sinal de igual). Em outros lugares você pode apenas usar title. Veja a edição em minha resposta para um exemplo.
maček de

2
O problema no Edit4 é que você tem apenas um caractere - não mais uma string - portanto, ele não reconhecerá a função string "capitalize".
Taryn East

O problema com o Edit 5 é que o título [0] é um fixnum, portanto, chamar o título [0] .to_s apenas fornecerá o número do caractere (ou seja, 121 como uma string: "121"). Você pode fazer self.title [0] = title.first.capitalize se quiser!
Nick

Eu adicionei um #upcase_first_case e fiz uma solicitação de pull: github.com/rails/rails/pull/15319 . Sinta-se à vontade para adicionar seu feedback aqui.
Aldo 'xoen' Giambelluca

Respostas:


93

Titleize irá capitalizar cada palavra. Esta linha parece pesada, mas garantirá que a única letra alterada seja a primeira.

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

Atualizar:

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..."

Espere, ainda não está funcionando. Alarme falso: / Acho que estou implementando errado.
Daniel O'Connor,

1
Daniel - geralmente é bom "aceitar" uma resposta que resolveu seu problema. Você pode fazer isso clicando no "tique" à esquerda da resposta. :)
Taryn East

1
Não entendi bem a pergunta, caso contrário, gostaria de lhe dar 1 acima. Eu estava procurando por .titleize em vez de .capitalize. Obrigado mesmo assim Taryn!
Eric Wanchic de

OOC - Por que isso o impede de dar um voto positivo? Respondi corretamente à pergunta do autor original? Se você pensa assim - então vote positivamente. Não precisa ser dependente de mais nada ... :)
Taryn East

2
Então, aqui vai: s[0].capitalize + s[1..-1] if s.present?
Alex Escalante

126

Isso deve servir:

title = "test test"     
title[0] = title[0].capitalize
puts title # "Test test"

40
Ou mais concisamente,title[0] = title[0].capitalize
Jon Garvin

Esta é uma solução muito elegante.
Karew

1
@JonGarvin title [0] .capitalize não funciona (pelo menos com Ruby 1.8.7), pois title [0] retorna um Fixnum, e capitalize espera uma string .. então eu acho que title.first.capitalize é a maneira de ir.
Nick

2
pena que você não podetitle.first.capitalize!
Adam Waite

1
capitalizeconverte todas as letras após a primeira letra em minúsculas, então não funciona para a string apresentada na pergunta ("eu sou de Nova York").
Mark Schneider

57

Você pode usar humanizar. Se você não precisa de sublinhados ou outras letras maiúsculas em suas linhas de texto.

Entrada:

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

Resultado:

"I'm from new york..."

7
O OP queria especificamente evitar 'nova york'
phatmann

Hmm, de fato, um pouco rápido demais com a minha resposta.
Bartuzz

17
@Bartuzz Mesmo não sendo isso o que o OP queria, era exatamente o que eu estava procurando. Obrigado!
Yetti

new york, entretanto, seria não gramatical como nome próprio e deveria usar maiúsculas.
Shayne de

Esteja avisado, humanizeé o Rails, exatamente o método ActiveSupport. Rubi puro não pode fazer isso.
Penguin de

51
str = "this is a Test"
str.sub(/^./, &:upcase)
# => "This is a Test"

1
Conciso e elegante. Eu acredito que esta deve ser a melhor resposta.
Chris

Concordo. Acho que essa deve ser a resposta aceita.
Garry Pettet

Uma peculiaridade é que, uma vez que ^significa início de linha, "\nfoo"torna-se "\nFoo". Isso provavelmente é adequado para a maioria dos casos de uso. Uma vez que é um sube não um gsub, ainda será maiúscula apenas uma letra, mesmo com strings de várias linhas.
Henrik N

Pode-se obter a limitação acima usando str.sub(/\S/, &:upcase), que localizará o primeiro caractere diferente de espaço em branco e o colocará em letras maiúsculas.
Anthony Panozzo

39

A partir do Rails 5.0.0.beta4 você pode usar o novo String#upcase_firstmétodo ou ActiveSupport::Inflector#upcase_firstfazê-lo. Verifique esta postagem do blog para mais informações.


Essas são ótimas notícias! Eu estava pensando no que podemos fazer agora e talvez um polyfill para Rails 4 seria bom.
hakunin

Observe que upcase_first e não lida com acentos / caracteres especiais, mesmo com mb_chars
user3033467

14

Uma solução orientada a objetos:

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

Então você pode apenas fazer isso:

"i'm from New York".capitalize_first_char

Pelo menos alguém escreveu uma solução elegante com extensão de Stringclasse.
Dmitriy

@Dmitriy por que o macaco remendar a classe de cordas é elegante?
Gerard Simpson


6

Editar 2

Não consigo reproduzir o seu problema. Vá em frente e execute este script Ruby nativo. Ele gera a saída exata que você está procurando, e Rails suporta todos esses métodos. Com que tipo de entrada você está tendo 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

resultado

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

Com base na sua edição, você pode tentar algo assim.

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

Isto irá fazer o truque

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

Ao tentar usar String#capitalizeem toda a string, você percebeu I'm from new yorkporque o método:

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"

+1 porque não pensei que funcionaria até tentar no meu pc :)
Jeriko

Oi, obrigado pela ajuda. O que estou fazendo de errado? Eu editei a pergunta original para incluir meu código.
Daniel O'Connor,

Usei a sugestão de Taryn e fiz funcionar. Obrigado pela ajuda!
Daniel O'Connor,

Olá, stackoverflow diz que você fez uma edição, mas não vejo nada diferente.
Daniel O'Connor,

6
my_string = "hello, World"
my_string.sub(/\S/, &:upcase) # => "Hello, World"

Não falha se my_string estiver vazia! Agradável. Isto é o que eu preciso.
Huliax

4

A maioria dessas respostas edita a string no local; quando você está apenas formatando para a saída de visualização, você pode não querer mudar a string subjacente para que possa usar tapdepois de duppara obter uma cópia editada

'test'.dup.tap { |string| string[0] = string[0].upcase }

3

Se e somente se OP quiser fazer monkey patching no objeto String, então isso pode ser usado

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

Agora use:

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

2

Uma versão ainda mais curta poderia ser:

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

2

Ninguém mencionou o gsub, o que permite que você faça isso de forma concisa.

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

Exemplo:

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

1

Talvez a maneira mais fácil.

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


0

E quanto ao método de classificação em string?

'somESTRIng'.classify

resultado:

#rails => 'SomESTRIng'

1
Ele está fazendo muitas coisas adicionais, como singularizar palavras. "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

Parece que sim. Eu sou novo no Ruby, e as outras respostas não fizeram o que o OP pediu, então fiz funcionar: D Corrija-me se eu estiver errado, mas AFAIK modificando uma string mudando a string [i] não trabalha em vários idiomas?
Jeriko

3
esta é uma pergunta específica do Ruby. Não importa se string[i]não funciona em outros idiomas. Ajude a manter o StackOverflow livre desse tipo de resposta hackeada. Não podemos dizer RTFM, mas mesmo uma rápida olhada nos Stringdocumentos teria ajudado a evitar uma resposta como esta ...
maček
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.