Comment mettre en majuscule la première lettre de chaque mot d'une chaîne?


589
s = 'the brown fox'

... fais quelque chose ici ...

s devrait être :

'The Brown Fox'

Quelle est la façon la plus simple de procéder?

Réponses:


991

La .title()méthode d'une chaîne (ASCII ou Unicode est très bien) fait ceci:

>>> "hello world".title()
'Hello World'
>>> u"hello world".title()
u'Hello World'

Cependant, recherchez les chaînes avec des apostrophes intégrées, comme indiqué dans la documentation.

L'algorithme utilise une définition simple indépendante de la langue d'un mot en tant que groupes de lettres consécutives. La définition fonctionne dans de nombreux contextes, mais cela signifie que les apostrophes dans les contractions et les possessifs forment des limites de mots, ce qui peut ne pas être le résultat souhaité:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

56
J'évite le problème possessif avec quelque chose comme" ".join(w.capitalize() for w in s.split())
mehtunguh

3
ce n'est pas sûr pour la plupart des chaînes car chaque mot, même possessif, est mis en majuscule.

10
Il y a un problème avec string.title (). Lorsque vous utilisez, par exemple "e g 3b", le résultat souhaité serait "E G 3b". Cependant, "e g 3b".title()revient "E G 3B".
Sören

7
Gardez à l'esprit que cela entraînera cela aussi:In [2]: 'tEst'.title() Out[2]: 'Test'
Jonas Libbrecht

4
Excellente réponse, et les commentaires soulignent qu'en python, tout ne se comporte pas comme vous en avez besoin, mais il existe toujours des moyens pratiques de le faire. Le moyen le plus pratique consiste souvent à importer une bibliothèque spécialement conçue, telle que python-titlecase
Aaron3468

189

La .title()méthode ne fonctionne pas bien,

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

Essayez la string.capwords()méthode,

import string
string.capwords("they're bill's friends from the UK")
>>>"They're Bill's Friends From The Uk"

Depuis les documents python sur capwords :

Divisez l'argument en mots en utilisant str.split (), mettez en majuscule chaque mot en utilisant str.capitalize () et joignez les mots en majuscule en utilisant str.join (). Si le deuxième argument facultatif sep est absent ou Aucun, les séquences de caractères d'espacement sont remplacées par un seul espace et les espaces de début et de fin sont supprimés, sinon sep est utilisé pour diviser et joindre les mots.


2
Capwords fait toujours défaut et ne gère pas quelque chose comme "There once was a string with an 'that had words right after it and then closed'". Avec cet exemple, tous les mondes à l'exception de thatsont capitalisés comme prévu. Les résultats étant"There Once Was A String With An 'that Had Words Right After It And Then Closed'"
devonbleibtrey

Pourtant, cela fonctionne mieux que title()dans des situations normales. Dans ma situation, title()retourne une mauvaise sortie pour les noms avec des accents ou une diérèse, tout en le capwords()gérant correctement.
houcros

1
Bien, mais cela gâche toujours la distinction "Uk / UK"
Jonath P

1
@Chen Houwu, UK / UK est un parfait contre-exemple. Comment empêcher Python de mettre en minuscule les majuscules existantes en utilisant une méthode similaire?
h0r53 Il y a

105

Juste parce que ce genre de chose est amusant pour moi, voici deux autres solutions.

Divisez en mots, initialisez chaque mot des groupes divisés et rejoignez. Cela changera l'espace blanc séparant les mots en un seul espace blanc, quel qu'il soit.

s = 'the brown fox'
lst = [word[0].upper() + word[1:] for word in s.split()]
s = " ".join(lst)

EDIT: Je ne me souviens pas de ce à quoi je pensais quand j'ai écrit le code ci-dessus, mais il n'est pas nécessaire de construire une liste explicite; nous pouvons utiliser une expression de générateur pour le faire de façon paresseuse. Voici donc une meilleure solution:

s = 'the brown fox'
s = ' '.join(word[0].upper() + word[1:] for word in s.split())

Utilisez une expression régulière pour faire correspondre le début de la chaîne, ou des mots séparant les espaces blancs, plus un seul caractère non blanc; utilisez des parenthèses pour marquer les "groupes de correspondance". Écrivez une fonction qui prend un objet de correspondance et renvoie le groupe de correspondance des espaces blancs inchangé et le groupe de correspondance des caractères non blancs en majuscules. Utilisez ensuite re.sub()pour remplacer les motifs. Celui-ci n'a pas les problèmes de ponctuation de la première solution, ni ne refait l'espace blanc comme ma première solution. Celui-ci produit le meilleur résultat.

import re
s = 'the brown fox'

def repl_func(m):
    """process regular expression match groups for word upper-casing problem"""
    return m.group(1) + m.group(2).upper()

s = re.sub("(^|\s)(\S)", repl_func, s)


>>> re.sub("(^|\s)(\S)", repl_func, s)
"They're Bill's Friends From The UK"

Je suis content d'avoir fait des recherches sur cette réponse. Je n'avais aucune idée que cela re.sub()pourrait prendre une fonction! Vous pouvez faire un traitement non trivial à l'intérieur re.sub()pour produire le résultat final!


1
+1 pour la solution à l'aide de tranches. J'avais besoin de quelque chose qui capitaliserait les premières lettres sans altérer la capitalisation du reste des mots (par exemple Foo devient foo, mais FOO devient fOO). C'était parfait.
TomNysetvold

1
capitalize renvoie son premier caractère en majuscule et le reste en minuscule
Vanuan

@Vanuan, vous avez raison! La description de la chaîne de doc m'a fait penser que tout ce qu'elle a fait était de mettre la première lettre en majuscule, mais vous avez raison sur ce qu'elle fait réellement. Je vais modifier la réponse. Merci pour l'avertissement.
steveha

Cela semble être le string.capwordscas, selon la documentation dans la réponse de Chen Houwu.
Adrian Keister

1
Quelque chose à noter dans la réponse ci-dessus, au lieu d'utiliser s.split (), je pense qu'il vaut mieux utiliser s.split (''). En effet, si la chaîne contient des espaces doubles et que vous souhaitez conserver ces espaces doubles lors de la jointure, s.plit ('') vous aidera à conserver les espaces alors que s.split () ne le fera pas
manpikin

21

Voici un résumé des différentes façons de le faire, elles fonctionneront pour toutes ces entrées:

""           => ""       
"a b c"      => "A B C"             
"foO baR"    => "FoO BaR"      
"foo    bar" => "Foo    Bar"   
"foo's bar"  => "Foo's Bar"    
"foo's1bar"  => "Foo's1bar"    
"foo 1bar"   => "Foo 1bar"     

- La solution la plus simple consiste à diviser la phrase en mots et à mettre la première lettre en majuscule, puis à la recoller:

# Be careful with multiple spaces, and empty strings
# for empty words w[0] would cause an index error, 
# but with w[:1] we get an empty string as desired
def cap_sentence(s):
  return ' '.join(w[:1].upper() + w[1:] for w in s.split(' ')) 

- Si vous ne voulez pas d'abord diviser la chaîne d'entrée en mots et utiliser des générateurs de fantaisie:

# Iterate through each of the characters in the string and capitalize 
# the first char and any char after a blank space
from itertools import chain 
def cap_sentence(s):
  return ''.join( (c.upper() if prev == ' ' else c) for c, prev in zip(s, chain(' ', s)) )

- Ou sans importer d'itertools:

def cap_sentence(s):
  return ''.join( (c.upper() if i == 0 or s[i-1] == ' ' else c) for i, c in enumerate(s) )

- Ou vous pouvez utiliser des expressions régulières, de la réponse de steveha :

# match the beginning of the string or a space, followed by a non-space
import re
def cap_sentence(s):
  return re.sub("(^|\s)(\S)", lambda m: m.group(1) + m.group(2).upper(), s)

Maintenant, voici quelques autres réponses qui ont été publiées et des entrées pour lesquelles elles ne fonctionnent pas comme prévu si nous utilisons la définition d'un mot comme début de phrase ou quoi que ce soit après un espace vide:

  return s.title()

# Undesired outputs: 
"foO baR"    => "Foo Bar"       
"foo's bar"  => "Foo'S Bar" 
"foo's1bar"  => "Foo'S1Bar"     
"foo 1bar"   => "Foo 1Bar"      

  return ' '.join(w.capitalize() for w in s.split())    
  # or
  import string
  return string.capwords(s)

# Undesired outputs:
"foO baR"    => "Foo Bar"      
"foo    bar" => "Foo Bar"      

l'utilisation de '' pour la division fixera la deuxième sortie, mais capwords () ne fonctionnera toujours pas pour la première

  return ' '.join(w.capitalize() for w in s.split(' '))    
  # or
  import string
  return string.capwords(s, ' ')

# Undesired outputs:
"foO baR"    => "Foo Bar"      

Soyez prudent avec plusieurs espaces vides

  return ' '.join(w[0].upper() + w[1:] for w in s.split())
# Undesired outputs:
"foo    bar" => "Foo Bar"                 

+1 pour un résumé complet. Je cherche un moyen de ne mettre en majuscule qu'un mot après un nombre (pas tous les mots). Pourriez-vous apporter un complément à votre réponse qui le démontre? Par exemple, lower 123 upperdevrait revenir lower 123 Upper, où le upperest en majuscule comme il suit un nombre. Je sais que cela dépasse la portée de la question du PO, mais c'est un complément intéressant à votre réponse déjà détaillée. Merci d'avance.
ProGrammer

Vous pouvez modifier certaines des méthodes ci-dessus pour répondre à vos besoins dans ce cas. Cependant, je ne l'ajouterais pas dans la réponse, car ce n'est pas ce que la plupart des gens recherchent. J'utiliserais la version regex pour cela, et utiliserais à la "([0-9]+)(\s+.)"place de "(^|\s)(\S)"(faire correspondre un ou plusieurs nombres, suivi d'un ou plusieurs espaces, et n'importe quel caractère après), ou "([0-9]+)(\s*.)"si vous voulez mettre en majuscule le caractère après 'zéro ou plusieurs' espaces après le number
aljgom

Je ne manquerai pas de l'examiner, cela m'a fait penser à un autre cas spécial: comment modifieriez-vous les extraits ci-dessus pour prendre une chaîne, par exemple WW1 - the great waret la sortie WW1 - The Great Warau lieu de Ww1 .... Voir le problème avec les abréviations? Seriez-vous prêt à ajouter quelque chose qui illustre ce cas? Je me pose des questions à ce sujet depuis un certain temps maintenant et je ne vois pas comment le faire.
ProGrammer

Les premières façons indiquées ci-dessus ne changent pas les lettres qui étaient déjà en majuscule dans la chaîne d'entrée, donc elles WW1sortiraient commeWW1
aljgom

15

Version prête à copier-coller de @jibberia anwser:

def capitalize(line):
    return ' '.join(s[:1].upper() + s[1:] for s in line.split(' '))

2
Pas besoin de construire une liste. str.joinaccepte les générateurs.
warvariuc

@warvariuc comment changeriez-vous ce code pour tirer parti des générateurs?
Konstantin Spirin

1
Supprimez simplement les crochets, comme c'est fait ici
warvariuc

1
Bien que @warvariuc soit parfait pour mentionner qu'il joinaccepte les exps gen, dans le cas str.joinparticulier, il est généralement préférable d'utiliser une compréhension de liste. En effet, il joinrépète deux fois l'argument et il est donc plus rapide de fournir une liste prête à l'emploi plutôt qu'un générateur.
Bhargav Rao

1
@BhargavRao pourquoi aurait-il str.joinbesoin de répéter deux fois l'argument? Je viens de vérifier - ce n'est pas le cas. Cependant, pour les petites séquences, la compréhension de la liste est en fait plus rapide.
warvariuc

12

Pourquoi compliquez-vous votre vie avec des jointures et des boucles alors que la solution est simple et sûre ??

Faites juste ceci:

string = "the brown fox"
string[0].upper()+string[1:]

2
Parce qu'il peut y avoir plusieurs mots.
Arnaud

1
Oui, mais souvent je veux seulement mettre en majuscule la première lettre. C'est une façon de le faire.
Deleet

1
Ne voudriez-vous donc pas simplement utiliser "the brown fox".capitalize()?
luckydonald

2
@luckydonald Parce que peut-être je ne veux pas 'this is John'devenir 'This is john'.
janek37

N'est-ce pas une meilleure façon de le faire simplement string.capitalize()(en écho essentiellement à @luckydonald)
Hassan Baig

10

Si str.title () ne fonctionne pas pour vous, faites la capitalisation vous-même.

  1. Fractionner la chaîne en une liste de mots
  2. Mettre en majuscule la première lettre de chaque mot
  3. Joignez les mots en une seule chaîne

Bon mot:

>>> ' '.join([s[0].upper() + s[1:] for s in "they're bill's friends from the UK".split(' ')])
"They're Bill's Friends From The UK"

Exemple clair:

input = "they're bill's friends from the UK"
words = input.split(' ')
capitalized_words = []
for word in words:
    title_case_word = word[0].upper() + word[1:]
    capitalized_words.append(title_case_word)
output = ' '.join(capitalized_words)

1
Un point intéressant avec cette solution est que vous perdez tout espace spécial. Peut ne pas être important selon le contexte.
mklauber

8

Si seulement vous voulez la première lettre:

>>> 'hello world'.capitalize()
'Hello world'

Mais pour capitaliser chaque mot:

>>> 'hello world'.title()
'Hello World'

Attention car 'hello New York'.capitalize()est'Hello new york'
user2314737

5

Une chaîne vide soulèvera une erreur si vous accédez à [1:], donc j'utiliserais:

def my_uppercase(title):
    if not title:
       return ''
    return title[0].upper() + title[1:]

pour mettre en majuscule uniquement la première lettre.


N'est-ce pas pour ça str.capitalize?
Eugene Pakhomov

4
@Eugene, oui mais malheureusement, mettez en minuscule toutes les autres lettres qui pourraient ne pas être souhaitables. : /
Wim Feijen

return title[:1].upper() + title[1:]s'occuperait également de ce problème puisque trancher la chaîne vide comme cela donnerait 2 chaînes vides, réunies pour créer une chaîne vide qui est retournée
aljgom

3

Comme Mark l'a souligné, vous devez utiliser .title():

"MyAwesomeString".title()

Cependant, si vous souhaitez mettre la première lettre en majuscule dans un modèle django , vous pouvez utiliser ceci:

{{ "MyAwesomeString"|title }}

ou en utilisant une variable:

{{ myvar|title }}

3

La méthode suggérée str.title () ne fonctionne pas dans tous les cas. Par exemple:

string = "a b 3c"
string.title()
> "A B 3C"

au lieu de "A B 3c".

Je pense qu'il vaut mieux faire quelque chose comme ça:

def capitalize_words(string):
    words = string.split(" ") # just change the split(" ") method
    return ' '.join([word.capitalize() for word in words])

capitalize_words(string)
>'A B 3c'

1
cependant une erreur peut survenir si le nombre d'espaces les séparant n'est pas 1. Pour référence: problème de
piratage

3

Bien que toutes les réponses soient déjà satisfaisantes, je vais essayer de couvrir les 2 cas supplémentaires ainsi que tous les cas précédents.

si les espaces ne sont pas uniformes et que vous souhaitez les conserver

string = hello    world i  am    here.

si toute la chaîne ne commence pas par des alphabets

string = 1 w 2 r 3g

Ici, vous pouvez utiliser ceci

def solve(s):
    a = s.split(' ')
    for i in range(len(a)):
        a[i]= a[i].capitalize()
    return ' '.join(a)

cela vous donnera

output = Hello    World I  Am    Here
output = 1 W 2 R 3g

J'espère que ce n'est pas redondant.


2
Merci d'avoir mis en évidence le cas d'espaces non uniformes. Certaines réponses ci-dessus utilisent s.split () au lieu de s.split (''). Il est important de noter que pour les espaces non uniformes, utiliser s.split ('') garantira le maintien des espaces non uniformes! Merci encore
manpikin

Cela fonctionne parfaitement pour les mots avec des espaces irréguliers ou des mots commençant par un chiffre. Merci :)
Amresh Giri

2

Pour mettre des mots en majuscules ...

str = "this is string example....  wow!!!";
print "str.title() : ", str.title();

@ Commentaire de Gary02127, sous le titre de travail de la solution avec apostrophe

import re

def titlecase(s):
    return re.sub(r"[A-Za-z]+('[A-Za-z]+)?", lambda mo: mo.group(0)[0].upper() + mo.group(0)[1:].lower(), s)

text = "He's an engineer, isn't he? SnippetBucket.com "
print(titlecase(text))

Utiliser la fonction existante donne une exécution rapide en python.
Tejas Tank

Je n'aime pas trop le titre (), car il ne gère pas les apostrophes. "Je ne peux pas dire" .title () donne "Je ne peux pas dire"
Gary02127

@ Gary02127 J'ai eu une réponse mise à jour, s'il vous plaît jetez un œil, a parfaitement fonctionné avec votre domaine de problème
Tejas Tank

1

Ne négligez pas la préservation de l'espace blanc. Si vous voulez traiter 'fred flinstone'et que vous obtenez 'Fred Flinstone'au lieu de 'Fred Flinstone', vous avez corrompu votre espace blanc. Certaines des solutions ci-dessus perdront de l'espace blanc. Voici une solution qui convient à Python 2 et 3 et qui préserve l'espace blanc.

def propercase(s):
    return ''.join(map(''.capitalize, re.split(r'(\s+)', s)))

0

Une fonction rapide a fonctionné pour Python 3

Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> capitalizeFirtChar = lambda s: s[:1].upper() + s[1:]
>>> print(capitalizeFirtChar('помните своих Предковъ. Сражайся за Правду и Справедливость!'))
Помните своих Предковъ. Сражайся за Правду и Справедливость!
>>> print(capitalizeFirtChar('хай живе вільна Україна! Хай живе Любовь поміж нас.'))
Хай живе вільна Україна! Хай живе Любовь поміж нас.
>>> print(capitalizeFirtChar('faith and Labour make Dreams come true.'))
Faith and Labour make Dreams come true.

0

Capitaliser la chaîne avec des espaces non uniformes

Eh bien, je comprends que c'est une vieille question et les réponses ont probablement presque été épuisées, mais je voudrais ajouter au point @Amit Gupta des espaces non uniformes. À partir de la question d'origine, nous aimerions mettre en majuscule chaque mot de la chaîne s = 'the brown fox'. Et si la chaîne était s = 'the brown fox'avec des espaces non uniformes.

def solve(s):
    # if you want to maintain the spaces in the string, s = 'the brown      fox'
    # use s.split(' ') instead of s.split(). 
    # s.split() returns ['the', 'brown', 'fox']
    # while s.split(' ') returns ['the', 'brown', '', '', '', '', '', 'fox']
    capitalized_word_list = [word.capitalize() for word in s.split(' ')]
    return ' '.join(capitalized_word_list)

.. votre code ne parvient pas à compenser les tabulations si ce ne sont pas des espaces blancs entre le brun et le renard ;-)
ZF007

-1

** Si vous souhaitez réduire la taille **

 #Assuming you are opening a new file   
 with open(input_file) as file:
     lines = [x for x in reader(file) if x]
 #for loop to parse the file by line
 for line in lines:
           name = [x.strip().lower() for x in line if x]
           print(name) #check the result

-2

J'aime vraiment cette réponse:

Version prête à copier-coller de @jibberia anwser:

def capitalize(line):
    return ' '.join([s[0].upper() + s[1:] for s in line.split(' ')])

Mais certaines des lignes que j'envoyais séparaient des caractères vierges '' qui provoquaient des erreurs lors de la tentative de s [1:]. Il y a probablement une meilleure façon de le faire, mais j'ai dû ajouter un si len (s)> 0, comme dans

return ' '.join([s[0].upper() + s[1:] for s in line.split(' ') if len(s)>0])

2
C'est trop compliqué, wth même vous allez vérifier la longueur?! inefficace.
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.