Capitaliser uniquement le premier caractère de la chaîne et laisser les autres seuls? (Rails)

102

J'essaie de faire en sorte que Rails capitalise le premier caractère d'une chaîne et laisse tous les autres tels quels. Je rencontre un problème où «je suis de New York» se transforme en «je viens de New York».

Quelle méthode utiliserais-je pour sélectionner le premier caractère?

Merci

EDIT: J'ai essayé d'implémenter ce que macek a suggéré, mais j'obtiens une erreur "méthode non définie` capitalize '" . Le code fonctionne bien sans la ligne de capitalisation. Merci pour l'aide!

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: ça marche. Merci pour l'aide!

EDIT 3: Attendez, non je n'ai pas ... Voici ce que j'ai dans mon modèle de liste.

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: J'ai essayé l'édition de macek, et j'ai toujours une erreur de méthode non définie "capitalize" " . Qu'est-ce que je pourrais faire de 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

EDIT 5: C'est bizarre. Je suis en mesure de me débarrasser de l'erreur de méthode non définie en utilisant la ligne ci-dessous. Le problème est qu'il semble remplacer la première lettre par un chiffre. Par exemple, au lieu de mettre en majuscule le y dans You , il transforme le y en un 121

self.title[0] = title[0].to_s.capitalize
Daniel O'Connor
la source
Sur la base de EDIT 3, vous devez commencer la ligne 2 avec self.title = . De plus, sur les 3 lignes, vous n'avez besoin que self.titlede la gauche d'un =(signe égal). Dans d'autres endroits, vous pouvez simplement utiliser title. Voir la modification sur ma réponse pour un exemple.
maček
2
Le problème dans Edit4 est que vous n'avez qu'un caractère - plus une chaîne - donc il ne reconnaîtra pas la fonction de chaîne "capitalize".
Taryn East
Le problème avec Edit 5 est que title [0] est un fixnum, donc appeler title [0] .to_s vous donnera simplement le numéro du caractère (c'est-à-dire 121 sous forme de chaîne: "121"). Vous pouvez faire self.title [0] = title.first.capitalize si vous le souhaitez!
Nick
J'ai ajouté un #upcase_first_case et fait une pull request: github.com/rails/rails/pull/15319 . N'hésitez pas à y ajouter vos commentaires.
Aldo 'xoen' Giambelluca

Réponses:

93

Titleize mettra en majuscule chaque mot. Cette ligne semble lourde, mais garantira que la seule lettre modifiée est la première.

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

Mettre à jour:

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 Est
la source
Attendez, ne fonctionne toujours pas. Fausse alarme: / Je pense que je l'implémente mal.
Daniel O'Connor
1
Daniel - c'est généralement une bonne forme "d'accepter" une réponse qui a résolu votre problème. Vous pouvez le faire en cliquant sur la "coche" à gauche de la réponse. :)
Taryn East
1
J'ai mal compris la question, sinon je voulais vous donner un 1. Je cherchais .titleize au lieu de .capitalize. Merci quand même Taryn!
Eric Wanchic
OOC - Pourquoi cela vous empêche-t-il de donner un vote favorable? Ai-je répondu correctement à la question de l'affiche originale? Si vous pensez que oui, alors votez pour. Il ne doit dépendre de rien d'autre ... :)
Taryn East
2
Alors, ça y est: s[0].capitalize + s[1..-1] if s.present?
Alex Escalante
126

Cela devrait le faire:

title = "test test"     
title[0] = title[0].capitalize
puts title # "Test test"
Pascal Van Hecke
la source
40
Ou plus brièvement,title[0] = title[0].capitalize
Jon Garvin
C'est une solution très élégante.
Karew le
1
@JonGarvin title [0] .capitalize ne fonctionne pas (au moins avec Ruby 1.8.7), car title [0] renvoie un Fixnum, et capitalize attend une chaîne .. donc je pense que title.first.capitalize est le moyen de aller.
Nick
2
honte que tu ne peux pastitle.first.capitalize!
Adam Waite
1
capitalizeconvertit toutes les lettres après la première lettre en minuscules, donc cela ne fonctionne pas pour la chaîne présentée dans la question ("je viens de New York").
Mark Schneider
57

Vous pouvez utiliser humaniser. Si vous n'avez pas besoin de traits de soulignement ou d'autres majuscules dans vos lignes de texte.

Contribution:

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

Production:

"I'm from new york..."
Bartuzz
la source
7
L'OP voulait spécifiquement éviter `` New York ''
phatmann
Hmm en effet, un peu trop vite avec ma réponse.
Bartuzz
17
@Bartuzz Même si ce n'est pas ce que voulait OP, c'est exactement ce que je cherchais. Merci!
Yetti
New York cependant serait non grammaticale car c'est un nom propre et devrait utiliser des majuscules.
Shayne
Soyez averti, humanizec'est la méthode Rails, exactement ActiveSupport. Le rubis uni ne peut pas faire cela.
Penguin
51
str = "this is a Test"
str.sub(/^./, &:upcase)
# => "This is a Test"
Lit superposé Lasse
la source
1
Concis et élégant. Je pense que cela devrait être la meilleure réponse.
Chris
Je suis d'accord. Je pense que cela devrait être la réponse acceptée.
Garry Pettet
Une bizarrerie est que puisque ^signifie début de ligne, "\nfoo"devient "\nFoo". C'est probablement bien pour la plupart des cas d'utilisation. Puisqu'il s'agit d'un subet non d'un gsub, il ne mettra toujours qu'une seule lettre, même avec des chaînes multilignes.
Henrik N
Peut obtenir la limitation ci-dessus en utilisant str.sub(/\S/, &:upcase), qui trouvera le premier caractère non blanc et le valorisera.
Anthony Panozzo
39

Depuis Rails 5.0.0.beta4, vous pouvez utiliser la nouvelle String#upcase_firstméthode ou ActiveSupport::Inflector#upcase_firstpour le faire. Consultez cet article de blog pour plus d'informations.

utilisateur1519240
la source
Ce sont de bonnes nouvelles! Je pensais à ce que nous pouvons faire maintenant et peut-être qu'un polyfill pour Rails 4 serait bien.
hakunin le
Notez que upcase_first et ne gère pas les accents / caractères spéciaux, même avec mb_chars
user3033467
14

Une solution orientée objet:

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

Ensuite, vous pouvez simplement faire ceci:

"i'm from New York".capitalize_first_char
lmanners
la source
Au moins quelqu'un a écrit une solution élégante avec extension de Stringclasse.
Dmitriy le
@Dmitriy Pourquoi monkey corrige-t-il la classe de chaînes de manière élégante?
Gerard Simpson
7
str.sub(/./, &:capitalize)
emlai
la source
6

Modifier 2

Je n'arrive pas à reproduire votre problème. Allez-y et exécutez ce script Ruby natif. Il génère la sortie exacte que vous recherchez et Rails prend en charge toutes ces méthodes. Avec quel type d'entrées rencontrez-vous des problèmes?

#!/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

production

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

Éditer

En fonction de votre modification, vous pouvez essayer quelque chose comme ça.

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

Ça fera l'affaire

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

En essayant d'utiliser String#capitalizesur toute la chaîne, vous voyiez I'm from new yorkparce que la méthode:

Renvoie une copie de str avec le premier caractère converti en majuscule et le reste en minuscule.

"hello".capitalize    #=> "Hello"
"HELLO".capitalize    #=> "Hello"
"123ABC".capitalize   #=> "123abc"
maček
la source
+1 parce que je ne pensais pas que cela fonctionnerait jusqu'à ce que je l'ai essayé sur mon PC :)
Jeriko
Salut, merci pour l'aide. Mais qu'est-ce que je fais de mal? J'ai modifié la question d'origine pour inclure mon code.
Daniel O'Connor
J'ai utilisé la suggestion de Taryn et je l'ai fait fonctionner. Merci pour l'aide en tout cas!
Daniel O'Connor
Salut, stackoverflow dit que vous avez fait une modification, mais je ne vois rien de différent?
Daniel O'Connor
6
my_string = "hello, World"
my_string.sub(/\S/, &:upcase) # => "Hello, World"
Pavel Pravosud
la source
N'échoue pas si my_string est vide! Agréable. C'est de quoi j'ai besoin.
Huliax
4

La plupart de ces réponses modifient la chaîne en place, lorsque vous formatez simplement pour la sortie de la vue, vous ne voudrez peut-être pas changer la chaîne sous-jacente afin que vous puissiez utiliser tapaprès a duppour obtenir une copie modifiée

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

Si et seulement si OP souhaite effectuer un patching de singe sur un objet String, cela peut être utilisé

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

Maintenant, utilisez-le:

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

Une version encore plus courte pourrait être:

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

Personne n'a mentionné gsub, ce qui vous permet de le faire de manière concise.

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

Exemple:

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

Peut-être le moyen le plus simple.

s = "test string"
s[0] = s[0].upcase
# => "Test string"
Lukas Baliak
la source
1

Notez que si vous avez besoin de traiter des caractères multi-octets, c'est à dire si vous devez internationaliser votre site, la s[0] = ...solution ne sera pas adéquate. Cette question de débordement de pile suggère d'utiliser la gemme unicode-util

Ruby 1.9: Comment puis-je correctement upcase & downcase multibyte strings?

ÉDITER

En fait, un moyen plus simple d'éviter au moins les encodages de chaînes étranges est d'utiliser simplement String # mb_chars :

s = s.mb_chars
s[0] = s.first.upcase
s.to_s
beauté
la source
0

Qu'en est-il de la méthode de classification sur chaîne?

'somESTRIng'.classify

production:

#rails => 'SomESTRIng'
mArtinko5MB
la source
1
Cela fait beaucoup de choses supplémentaires, comme des mots singuliers. "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
la source
Semble si. Je suis nouveau dans ruby, et les autres réponses n'ont pas vraiment fait ce que l'OP m'a demandé, alors je l'ai fait fonctionner: D Corrigez-moi si je me trompe, mais AFAIK modifie une chaîne en changeant la chaîne [i] ne le fait pas travailler dans de nombreuses langues?
Jeriko
3
c'est une question spécifique à Ruby. Peu importe si string[i]cela ne fonctionne pas dans d'autres langues. S'il vous plaît, aidez à garder StackOverflow sans encombrement de ce genre de réponses piratées. Nous ne pouvons pas dire RTFM, mais même un rapide coup d'œil à la Stringdocumentation aurait aidé à éviter une réponse comme celle-ci ...
maček