Comment mettre en majuscule la première lettre d'une chaîne en Ruby


134

La upcaseméthode met en majuscule la chaîne entière, mais je n'ai besoin de mettre en majuscule que la première lettre.

De plus, je dois prendre en charge plusieurs langues populaires, comme l'allemand et le russe.

Comment fait-on ça?


4
Sachez que certaines langues ont des idées différentes sur la première lettre à mettre en majuscule. En irlandais, vous faites des choses comme "i mBaile Átha Cliath" ("à Dublin") - minuscule 'm', majuscule 'B'. (Voir en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages si vous êtes curieux de savoir pourquoi l'Irlandais ferait cela et pourquoi cela a du sens.)
James Moore

3
Et sachez également que #capitalize réduira la casse de toutes les lettres qui ne sont pas la première lettre ... ce qui n'est pas toujours ce que vous voulez. ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa']
Huliax

Réponses:


260

Cela dépend de la version de Ruby que vous utilisez:

Ruby 2.4 et supérieur:

Cela fonctionne simplement, car Ruby v2.4.0 prend en charge le mappage de cas Unicode:

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

Ruby 2.3 et inférieur:

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

Le problème est qu'il ne fait tout simplement pas ce que vous voulez, il sort à la марияplace Мария.

Si vous utilisez Rails, il existe une solution de contournement simple:

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

Sinon, vous devrez installer le gem unicode et l'utiliser comme ceci:

require 'unicode'

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

Rubis 1.8:

Assurez-vous d'utiliser le commentaire magique de codage :

#!/usr/bin/env ruby

puts "мария".capitalize

donne invalid multibyte char (US-ASCII), tandis que:

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

puts "мария".capitalize

fonctionne sans erreur, mais voyez aussi la section "Ruby 2.3 et inférieur" pour une vraie capitalisation.


19
Notez que "my API is great".capitalizecela produira apparemment ce My api is greatqui est probablement un comportement indésirable. Donc, cette réponse ne répond pas vraiment à la question car il ne veut que la PREMIÈRE lettre en majuscules et les autres intactes.
Daniel AR Werner le

55

mettre en majuscule la première lettre du premier mot de la chaîne

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

mettre en majuscule la première lettre de chaque mot

Dans les rails:

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

OU

"kirk_douglas".titleize
=> "Kirk Douglas"    

En rubis:

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

en dehors des rails, mais souhaitant toujours utiliser la méthode titleize

require 'active_support/core_ext'
"kirk douglas".titleize #or capitalize

1
Votez pour une solution pure Ruby. Trop paresseux pour lancer Rails correctement, et cela a fait l'affaire :)
illbzo1

19

Malheureusement, il est impossible pour une machine de monter / descendre / capitaliser correctement. Il a besoin de beaucoup trop d'informations contextuelles pour qu'un ordinateur puisse le comprendre.

C'est pourquoi la Stringclasse Ruby ne prend en charge que les majuscules pour les caractères ASCII, car elle est au moins quelque peu bien définie.

Qu'est-ce que j'entends par «informations contextuelles»?

Par exemple, pour capitaliser icorrectement, vous devez savoir dans quelle langue le texte est. L'anglais, par exemple, n'a que deux is: majuscule Isans point et petit iavec un point. Mais le turc a quatre is: une majuscule Isans point, une majuscule İavec un point, une petite ısans un point, une petite iavec un point. Donc, en anglais 'i'.upcase # => 'I'et en turc 'i'.upcase # => 'İ'. En d'autres termes: comme 'i'.upcasepeut renvoyer deux résultats différents, selon la langue, il est évidemment impossible de mettre correctement en majuscule un mot sans connaître sa langue.

Mais Ruby ne connaît pas la langue, il ne connaît que l'encodage. Par conséquent, il est impossible de mettre correctement en majuscule une chaîne avec la fonctionnalité intégrée de Ruby.

Cela empire: même en connaissant la langue, il est parfois impossible de bien faire la capitalisation. Par exemple, en allemand, 'Maße'.upcase # => 'MASSE'( Maße est le pluriel de Maß qui signifie mesure ). Cependant, 'Masse'.upcase # => 'MASSE'(signifiant masse ). Alors, qu'est-ce que c'est 'MASSE'.capitalize? En d'autres termes: une capitalisation correcte nécessite une intelligence artificielle à part entière.

Ainsi, au lieu de donner parfois la mauvaise réponse, Ruby choisit parfois de ne donner aucune réponse du tout , c'est pourquoi les caractères non ASCII sont simplement ignorés dans les opérations downcase / upcase / capitalize. (Ce qui, bien sûr, donne également de mauvais résultats, mais au moins c'est facile à vérifier.)


4
Désolé, mais votre argumentation ne tient pas la route. Ce n'est pas vrai que Ruby choisisse de ne pas donner de réponse du tout, Ruby donne toujours une réponse, ce qui est souvent faux - par exemple "мария" .upcase ne doit jamais retourner "мария", ce qui n'est correct dans aucun contexte. Et vos digressions sur la nécessité de l'IA ne sont pas du tout pertinentes - rien n'empêche upcase de reprendre un tableau, dites ['I', 'İ'] pour 'i'.upcase, et de laisser l'appelant décider quelle capitalisation est pertinente dans une situation donnée. Actuellement, la gestion de Ruby de la conversion entre majuscules et minuscules est interrompue, et c'est tout.
michau

2
-1 parce qu'il y a une capitale Eszett . L'utilisation d'une zone non complètement formalisée ne peut pas servir de preuve que la solution n'est possible qu'avec l'IA.
Mike

15

Eh bien, juste pour que nous sachions comment mettre en majuscule uniquement la première lettre et laisser le reste seul, car parfois c'est ce que l'on souhaite:

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

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

L'appel capitalizeentraînerait ["Nasa", "Mhz", "Sputnik"].


Merci juste ce que je cherchais, utile pour convertir les titres en `` cas de phrase ''
Good Lux

2
word[0] = word[0].upcase
David

@David. NON! Cela modifie les valeurs des mots du tableau sur lequel #collect est appelé. C'est un mauvais effet secondaire.
Huliax

Je montrais un moyen plus simple de mettre en majuscule la première lettre d'un mot, en remplaçant les 3 lignes intérieures de cette solution, que j'ai clarifiée en utilisant la wordvariable. Bien sûr, si vous avez plus de mots, appelez-les tous! ;)words.map{|word| word[0] = word[0].upcase}
David

@David. Votre code équivaut à #capitalize!et non #capitalize. Ce dernier renvoie une nouvelle chaîne tandis que le premier modifie le récepteur de la méthode (dans ce cas, le récepteur est wordet la méthode est #[]). Si vous utilisiez votre code à l'intérieur d'un bloc #collect, vous vous retrouveriez avec deux tableaux différents avec les mêmes objets String dans chacun d'eux (et les chaînes auraient été modifiées). Ce n'est pas quelque chose que vous voudriez normalement faire. Même si vous en êtes conscient, les autres lecteurs devraient le comprendre.
Huliax

8

Rails 5+

Depuis Active Support et Rails 5.0.0.beta4, vous pouvez utiliser l'une des deux méthodes: String#upcase_firstou 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"

Vérifiez " Rails 5: Nouvelle méthode upcase_first " pour plus d'informations.


3

Utilisez capitalize. À partir de la documentation String :

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"

N'utilisez le point d'exclamation que si vous souhaitez que la chaîne d'origine soit modifiée.
Magnar

doh Merci, corrigé mon erreur.
jhwist

5
-1. L'OP mentionne explicitement le texte allemand et russe, ce qui implique des caractères non ASCII. String#upcase(et aussi String#downcase) ne sont définis que pour les caractères ASCII.
Jörg W Mittag

1
En utilisant Ruby 2.5.0 aujourd'hui et String#upcasesemble fonctionner correctement sur les caractères non-ASCII. 2.5.0 :001 > "мария".upcase => "МАРИЯ"
Huliax

1
@Huliax Comme mentionné dans la réponse acceptée, cela n'a été le cas que depuis Ruby 2.4.0 (qui a été publié en 2016).
nisetama

2

Vous pouvez utiliser mb_chars. Cela respecte umlaute:

class String

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

end

Exemple:

"ümlaute".capitalize_first
#=> "Ümlaute"

0

Voici une autre façon de mettre en majuscule chaque mot dans une chaîne. \wne correspond pas aux caractères cyrilliques ou aux caractères latins avec des signes diacritiques, mais le [[:word:]]fait. upcase, downcase, capitalizeEt swapcasene pas appliquer aux caractères non-ASCII jusqu'à ce que Ruby 2.4.0 qui a été publié 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:]] correspond aux caractères de ces catégories:

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

[[:word:]]correspond aux 10 caractères de la catégorie "Ponctuation, Connecteur" ( 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

C'est une autre façon de convertir uniquement le premier caractère d'une chaîne en majuscules:

"striNG".sub(/./,&:upcase)
=> "StriNG"
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.