Como colocar em maiúscula a primeira letra de cada palavra em uma string?

588
s = 'the brown fox'

... faça alguma coisa aqui ...

s deveria estar :

'The Brown Fox'

Qual é a maneira mais fácil de fazer isso?

TIMEX
fonte

Respostas:

990

O .title()método de uma sequência de caracteres (ASCII ou Unicode é bom) faz isso:

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

No entanto, procure seqüências de caracteres com apóstrofos incorporados, conforme observado nos documentos.

O algoritmo usa uma definição simples e independente de idioma de uma palavra como grupos de letras consecutivas. A definição funciona em muitos contextos, mas significa que apóstrofos em contrações e possessivos formam limites de palavras, o que pode não ser o resultado desejado:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"
Mark Rushakoff
fonte
56
I evitar o problema possessivo com algo parecido" ".join(w.capitalize() for w in s.split())
mehtunguh
3
isso não é seguro para a maioria das strings, porque todas as palavras até possessivas são maiúsculas.
10
Há um problema com string.title (). Quando você usa, por exemplo "e g 3b", o resultado desejado seria "E G 3b". No entanto, "e g 3b".title()retorna "E G 3B".
11116 Sören
7
Lembre-se de que isso também causará isso:In [2]: 'tEst'.title() Out[2]: 'Test'
Jonas Libbrecht 14/11
4
Ótima resposta e comentários destacam que, em python, nem tudo se comporta da maneira que você precisa, mas sempre existem maneiras convenientes de fazê-lo. A maneira mais conveniente é muitas vezes importar uma biblioteca construída propositadamente, como python-titlecase
Aaron3468
189

O .title()método não pode funcionar bem,

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

Tente string.capwords()método,

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

Nos documentos python sobre capwords :

Divida o argumento em palavras usando str.split (), coloque cada letra em maiúscula usando str.capitalize () e junte as palavras em maiúscula usando str.join (). Se o segundo argumento opcional sep estiver ausente ou None, as execuções de caracteres de espaço em branco serão substituídas por um único espaço e os espaços em branco à esquerda e à direita serão removidos; caso contrário, sep será usado para dividir e unir as palavras.

Chen Houwu
fonte
2
O Capwords ainda está ausente e não lida com algo como "There once was a string with an 'that had words right after it and then closed'". Neste exemplo, todos os mundos, exceto os, thatsão capitalizados conforme o esperado. Os resultados são #"There Once Was A String With An 'that Had Words Right After It And Then Closed'"
devonbleibtrey 25/03
Ainda assim, isso funciona melhor do que title()em situações normais. Na minha situação, title()retorna uma saída incorreta para nomes com acentos ou dieresis, enquanto capwords()manipulada corretamente.
houcros 20/09/16
1
Bom, mas ainda mexe-se o "UK / UK" distinção
Jonath P
1
@ Chen Houwu, Reino Unido / Reino Unido é um exemplo perfeito de contador. Como impedir que o Python minúsculas maiúsculas existentes usando um método semelhante?
h0r53
105

Só porque esse tipo de coisa é divertido para mim, aqui estão mais duas soluções.

Divida em palavras, limpe cada palavra dos grupos de divisão e junte-se novamente. Isso mudará o espaço em branco que separa as palavras em um único espaço em branco, não importa o que fosse.

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

EDIT: Não me lembro do que estava pensando quando escrevi o código acima, mas não há necessidade de criar uma lista explícita; podemos usar uma expressão geradora para fazê-lo de forma preguiçosa. Então, aqui está uma solução melhor:

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

Use uma expressão regular para corresponder ao início da sequência, ou espaço em branco que separa as palavras, além de um caractere que não seja um espaço em branco; use parênteses para marcar "grupos de correspondência". Escreva uma função que pegue um objeto de correspondência e retorne o grupo de correspondência de espaços em branco inalterado e o grupo de correspondência de caracteres que não sejam espaços em branco em maiúsculas. Em seguida, use re.sub()para substituir os padrões. Este não possui os problemas de pontuação da primeira solução, nem refaz o espaço em branco como minha primeira solução. Este produz o melhor resultado.

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"

Estou feliz por ter pesquisado esta resposta. Eu não tinha ideia de que re.sub()poderia ter uma função! Você pode fazer um processamento não trivial dentro re.sub()para produzir o resultado final!

steveha
fonte
1
+1 para a solução usando fatias. Eu precisava de algo que capitalizasse as primeiras letras maiúsculas sem alterar a capitalização do restante das palavras (por exemplo, Foo se torna foo, mas FOO se torna fOO). Isso foi perfeito.
TomNysetvold
1
capitalize retorna seu primeiro caractere em maiúscula e o restante em minúsculas
Vanuan
@Vanuan, você está certo! A descrição da sequência de documentos me fez pensar que tudo o que fez foi colocar em maiúscula a primeira letra, mas você está certo sobre o que ela realmente faz. Vou editar a resposta. Obrigado pelo aviso.
Steveha 3/12/12
Parece ser o que string.capwordsacontece, de acordo com a documentação na resposta de Chen Houwu.
Adrian Keister
1
Algo a observar na resposta acima, em vez de usar s.split (), acho que é melhor usar s.split (''). Isso ocorre porque a string possui alguns espaços duplos e você deseja manter esses espaços duplos na união, s.plit ('') ajudará a manter os espaços enquanto s.split () não
manpikin
21

Aqui está um resumo das diferentes maneiras de fazer isso, elas funcionarão para todas essas entradas:

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

- A solução mais simples é dividir a frase em palavras e colocar em maiúscula a primeira letra e depois juntá-la novamente:

# 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(' ')) 

- Se você não deseja dividir a sequência de entrada em palavras primeiro, e usando geradores sofisticados:

# 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 sem importar ferramentas:

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

- Ou você pode usar expressões regulares, a partir da resposta 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)

Agora, estas são algumas outras respostas que foram postadas e entradas para as quais elas não funcionam conforme o esperado, se estivermos usando a definição de uma palavra que é o início da frase ou qualquer coisa depois de um espaço em branco:

  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"      

usar '' para a divisão corrigirá a segunda saída, mas capwords () ainda não funcionará pela primeira

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

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

Tenha cuidado com vários espaços em branco

  return ' '.join(w[0].upper() + w[1:] for w in s.split())
# Undesired outputs:
"foo    bar" => "Foo Bar"                 
aljgom
fonte
+1 para um resumo abrangente. Estou procurando uma maneira de colocar apenas uma palavra em maiúscula após um número (nem todas as palavras). Você poderia acrescentar sua resposta que demonstra isso? Por exemplo, lower 123 upperdeve retornar lower 123 Upper, onde o upperé capitalizado como segue um número. Sei que vai além do escopo da pergunta do OP, mas é um bom complemento para a sua já extensa resposta. Desde já, obrigado.
ProGrammer
Você pode modificar alguns dos métodos acima para atender às suas necessidades neste caso. No entanto, eu não o adicionaria como parte da resposta, pois não é o que a maioria das pessoas está procurando. Eu usaria a versão regex para isso e, em "([0-9]+)(\s+.)"vez de "(^|\s)(\S)"(corresponder a um ou mais números, seguidos de um ou mais espaços e qualquer caractere depois), ou "([0-9]+)(\s*.)"se você quiser colocar o caractere em maiúscula após 'zero ou mais' espaços após o número
aljgom 07/01
Certifico-me de examinar isso, o que me fez pensar em outro caso especial: como você modificaria os trechos acima para pegar uma string, por exemplo, WW1 - the great ware output em WW1 - The Great Warvez de Ww1 .... Veja o problema com abreviações? Você gostaria de adicionar algo que demonstre esse caso? Eu estive pensando sobre isso por um tempo agora e não consigo pensar em uma maneira de fazê-lo.
ProGrammer
As primeiras maneiras mencionadas acima não mudam as letras que já estavam em maiúsculas na sequência de entrada, portanto WW1seriam WW1
exibidas
15

Versão pronta para copiar e colar do @jibberia anwser:

def capitalize(line):
    return ' '.join(s[:1].upper() + s[1:] for s in line.split(' '))
Konstantin Spirin
fonte
2
Não há necessidade de criar uma lista. str.joinaceita geradores.
precisa saber é o seguinte
@warvariuc como você alteraria esse código para alavancar geradores?
Konstantin Spirin
1
Basta remover os colchetes, como ele é feito aqui
warvariuc
1
Embora @warvariuc seja perfeito ao mencionar que joinaceita gen exps, no caso de str.joinparticularmente, geralmente é preferível usar uma lista de compreensão. Isso ocorre porque joinitera duas vezes sobre o argumento e, portanto, é mais rápido fornecer uma lista pronta para uso em vez de um gerador.
Bhargav Rao
1
@BhargavRao por que str.joinprecisaria repetir duas vezes sobre o argumento? Acabei de verificar - não. Embora para pequenas sequências a compreensão da lista seja mais rápida.
warvariuc
12

Por que você complica sua vida com junções e loops quando a solução é simples e segura?

Apenas faça o seguinte:

string = "the brown fox"
string[0].upper()+string[1:]
Brad Larson
fonte
2
Porque pode haver várias palavras.
Arnaud
1
Sim, mas muitas vezes só quero colocar em maiúscula a primeira letra. Esta é uma maneira de fazer isso.
Deleet 11/11
1
Você não usaria então "the brown fox".capitalize()?
luckydonald
2
@luckydonald Porque talvez eu não quero transformar 'this is John'em 'This is john'.
Janek37
Não é a melhor maneira de fazer isso simplesmente string.capitalize()(@luckydonald essencialmente ecoando)
Hassan Baig
10

Se str.title () não funcionar, faça você mesmo a capitalização.

  1. Divida a sequência em uma lista de palavras
  2. Coloque em maiúscula a primeira letra de cada palavra
  3. Junte as palavras em uma única sequência

Uma linha:

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

Exemplo claro:

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)
jibberia
fonte
1
Um ponto de interesse dessa solução é que você perde espaço em branco especial. Pode não ser importante, dependendo do contexto.
Mklauber 17/10/11
8

Se você quiser apenas a primeira letra:

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

Mas para capitalizar cada palavra:

>>> 'hello world'.title()
'Hello World'
Zahran
fonte
Cuidado porque 'hello New York'.capitalize()é'Hello new york'
user2314737 15/02
5

Uma string vazia gerará um erro se você acessar [1:]; portanto, eu usaria:

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

para maiúsculas apenas a primeira letra.

Wim Feijen
fonte
Não str.capitalizeé para isso que serve?
Eugene Pakhomov
4
@ Eugene, sim, mas infelizmente, coloque em maiúsculas todas as outras letras que podem não ser desejáveis. : /
Wim Feijen
return title[:1].upper() + title[1:]também cuidar desse problema, já que cortar a cadeia vazia como o que daria 2 cadeias vazias, unidas fazer uma cadeia vazia, que é devolvido
aljgom
3

Como Mark apontou, você deve usar .title():

"MyAwesomeString".title()

No entanto, se você quiser colocar a primeira letra em maiúscula dentro de um modelo de django , você pode usar o seguinte:

{{ "MyAwesomeString"|title }}

ou usando uma variável:

{{ myvar|title }}
chuckfinley
fonte
3

O método sugerido str.title () não funciona em todos os casos. Por exemplo:

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

em vez de "A B 3c".

Eu acho que é melhor fazer algo assim:

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'
Sören
fonte
1
no entanto erro pode surgir se o número de espaços que as separam não é 1. Para referência: problema hackerrank
Divakar Rajesh
3

Embora todas as respostas já sejam satisfatórias, tentarei cobrir os dois casos extras, juntamente com o caso anterior.

se os espaços não forem uniformes e você quiser manter o mesmo

string = hello    world i  am    here.

se toda a cadeia não estiver começando no alfabeto

string = 1 w 2 r 3g

Aqui você pode usar isso

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

isso vai te dar

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

Espero que isso não seja redundante.

Amit Gupta
fonte
2
Obrigado por destacar o caso de espaços não uniformes. Algumas respostas acima usam s.split () em vez de s.split (''). É importante observar que, para espaços não uniformes, usar s.split ('') garantirá que os espaços não uniformes sejam mantidos! Mais uma vez obrigado
manpikin 03/02
Isso funciona perfeitamente para palavras com espaços irregulares ou palavras que começam com algum dígito. Obrigado :)
Amresh Giri
2

Para capitalizar palavras ...

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

@ Gary02127 comentário, abaixo do título do trabalho da solução com apóstrofo

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))
Tejas Tank
fonte
Usar a função existente fornece execução rápida em python.
Tejas Tank
Não gosto muito de title (), pois ele não lida com apóstrofos. "Eu não posso dizer" .title () dá "Eu não posso dizer"
Gary02127
@ Gary02127 eu tinha atualizado resposta, por favor, dê uma olhada, perfeito trabalhou com seu domínio problema também
Tejas tanque
1

Não negligencie a preservação do espaço em branco. Se você deseja processar 'fred flinstone'e obtém, em 'Fred Flinstone'vez de 'Fred Flinstone', danificou seu espaço em branco. Algumas das soluções acima perderão espaço em branco. Aqui está uma solução que é boa para Python 2 e 3 e preserva o espaço em branco.

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

Uma função rápida funcionou para 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.
PADYMKO
fonte
0

Colocar letras maiúsculas em maiúsculas com espaços não uniformes

Bem, eu entendo que essa é uma pergunta antiga e provavelmente as respostas podem estar quase esgotadas, mas eu gostaria de acrescentar ao ponto de espaços não uniformes do @Amit Gupta. A partir da pergunta original, gostaríamos de capitalizar todas as palavras da string s = 'the brown fox'. E se a string estivesse s = 'the brown fox'com espaços não 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)
manpikin
fonte
.. seu código não compensa guias, se não houver espaços em branco entre marrom e raposa ;-)
ZF007 26/3
-1

** Caso você queira reduzir o tamanho **

 #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
Fouad Djebbar
fonte
-2

Eu realmente gosto desta resposta:

Versão pronta para copiar e colar do @jibberia anwser:

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

Mas algumas das linhas que eu estava enviando separavam alguns caracteres em branco '' que causavam erros ao tentar fazer s [1:]. Provavelmente existe uma maneira melhor de fazer isso, mas eu tive que adicionar um if len (s)> 0, como em

return ' '.join([s[0].upper() + s[1:] for s in line.split(' ') if len(s)>0])
user1475777
fonte
2
Isso é muito complicado, com o qual você verifica o comprimento ?! ineficiente.