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
Daniel O'Connor
fonte
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..."
Taryn East
fonte
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"
Pascal Van Hecke
fonte
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..."
Bartuzz
fonte
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"
Lasse Bunk
fonte
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.

user1519240
fonte
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
maneiras
fonte
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
7
str.sub(/./, &:capitalize)
emlai
fonte
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"
Macek
fonte
+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"
Pavel Pravosud
fonte
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 }
Paul.s
fonte
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
JVK
fonte
2

Uma versão ainda mais curta poderia ser:

s = "i'm from New York..."
s[0] = s.capitalize[0]
Saim
fonte
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"
mahemoff
fonte
1

Talvez a maneira mais fácil.

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

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

'somESTRIng'.classify

resultado:

#rails => 'SomESTRIng'
mArtinko5MB
fonte
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
Jeriko
fonte
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