Jak zapisać wielką literę każdego słowa w ciągu?

587
s = 'the brown fox'

... zrób coś tutaj ...

s Powinien być :

'The Brown Fox'

Jak najłatwiej to zrobić?

TIMEX
źródło

Odpowiedzi:

986

.title()Metoda łańcucha znaków (ASCII lub Unicode jest w porządku) to robi:

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

Należy jednak zwrócić uwagę na ciągi znaków z osadzonymi apostrofami, jak zauważono w dokumentacji.

Algorytm wykorzystuje prostą, niezależną od języka definicję słowa jako grupy kolejnych liter. Definicja działa w wielu kontekstach, ale oznacza, że ​​apostrofy w skurczach i dzierżawczy tworzą granice słów, co może nie być pożądanym rezultatem:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"
Mark Rushakoff
źródło
56
" ".join(w.capitalize() for w in s.split())
Unikam
3
nie jest to bezpieczne dla większości ciągów, ponieważ każde słowo, nawet dzierżawcze, jest pisane wielkimi literami.
10
Wystąpił problem z string.title (). Gdy użyjesz, na przykład, "e g 3b"pożądany wynik będzie "E G 3b". Jednak "e g 3b".title()powraca "E G 3B".
Sören,
7
Należy pamiętać, że spowoduje to również:In [2]: 'tEst'.title() Out[2]: 'Test'
Jonas Libbrecht
4
Świetna odpowiedź i komentarze podkreślają, że w Pythonie nie wszystko zachowuje się tak, jak trzeba, ale zawsze są wygodne sposoby, aby to zrobić. Najwygodniejszym sposobem jest często importowanie specjalnie zbudowanej biblioteki, takiej jak python-titlecase
Aaron3468,
189

.title()Metoda nie może działać dobrze,

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

Wypróbuj string.capwords()metodę

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

Z dokumentacji Pythona na temat haseł :

Podziel argument na słowa za pomocą str.split (), wielkie litery każdego słowa za pomocą str.capitalize () i połącz wielkie litery za pomocą str.join (). Jeśli opcjonalny drugi argument sep jest nieobecny lub Brak, przebiegi białych znaków są zastępowane pojedynczą spacją, a wiodące i końcowe białe spacje są usuwane, w przeciwnym razie sep służy do dzielenia i łączenia słów.

Chen Houwu
źródło
2
Brakuje haseł i nie obsługuje czegoś takiego jak "There once was a string with an 'that had words right after it and then closed'". W tym przykładzie wszystkie światy z wyjątkiem thatsą kapitalizowane zgodnie z oczekiwaniami. Rezultat jest"There Once Was A String With An 'that Had Words Right After It And Then Closed'"
devonbleibtrey
Mimo to działa to lepiej niż title()w normalnych sytuacjach. W mojej sytuacji title()zwraca zły wynik dla nazw z akcentami lub dieresis, gdy jest capwords()obsługiwany poprawnie.
houcros
Dobrze, ale nadal miesza się z wyróżnieniem „UK / UK”
Jonath P
104

Tylko dlatego, że tego rodzaju zabawa sprawia mi przyjemność, oto dwa kolejne rozwiązania.

Podziel na słowa, napisz początkowo każde słowo z podzielonych grup i dołącz ponownie. Spowoduje to zmianę białej przestrzeni oddzielającej słowa na jedną białą spację, bez względu na to, co to było.

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

EDYCJA: Nie pamiętam, o czym myślałem, kiedy pisałem powyższy kod, ale nie ma potrzeby budowania wyraźnej listy; możemy użyć wyrażenia generatora, aby zrobić to leniwie. Oto lepsze rozwiązanie:

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

Użyj wyrażenia regularnego, aby dopasować początek łańcucha lub spacji oddzielających słowa, a także pojedynczego znaku spacji; użyj nawiasów, aby zaznaczyć „dopasuj grupy”. Napisz funkcję, która pobiera obiekt dopasowania i zwraca niezmienioną grupę dopasowań białych znaków oraz grupę dopasowań znaków niebiałych dużymi literami. Następnie użyj, re.sub()aby zastąpić wzory. Ten nie ma problemów z interpunkcją pierwszego rozwiązania, ani nie przerabia białej przestrzeni jak moje pierwsze rozwiązanie. Ten daje najlepszy wynik.

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"

Cieszę się, że zbadałem tę odpowiedź. Nie miałem pojęcia, że re.sub()może przyjąć jakąś funkcję! Możesz wykonać nietrywialne przetwarzanie w re.sub()celu uzyskania ostatecznego rezultatu!

steveha
źródło
1
+1 za rozwiązanie wykorzystujące plastry. Potrzebowałem czegoś, co użyłoby wielkich liter bez zmiany wielkich liter pozostałych słów (np. Foo zmienia się w foo, ale Foo zmienia się w foo). To było idealne.
TomNysetvold
1
capitalize zwraca pierwszą literę wielką literą, a pozostałe małe litery
Vanuan
@Vanuan, masz rację! Opis ciągu dokumentów sprawił, że pomyślałem, że pierwsza litera była wielką literą, ale masz rację co do tego, co faktycznie robi. Zmienię odpowiedź. Dziękuję za heads-up.
steveha,
Wydaje się, że tak właśnie string.capwordsjest, zgodnie z dokumentacją zawartą w odpowiedzi Chen Houwu.
Adrian Keister
1
Należy zwrócić uwagę na powyższą odpowiedź, zamiast używać s.split (), myślę, że lepiej jest użyć s.split (''). Wynika to z faktu, że jeśli ciąg ma trochę podwójnych spacji i chcesz zachować te podwójne spacje podczas łączenia, s.plit ('') pomoże ci zachować te spacje, podczas gdy s.split () nie będzie
manpikin
21

Oto podsumowanie różnych sposobów, aby to zrobić, będą działać dla wszystkich tych danych wejściowych:

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

- Najprostszym rozwiązaniem jest podzielenie zdania na słowa i zapisanie pierwszej litery wielką literą, a następnie połączenie jej z powrotem:

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

- Jeśli nie chcesz najpierw podzielić łańcucha wejściowego na słowa i używając fantazyjnych generatorów:

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

- Lub bez importowania itertools:

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

- Lub możesz użyć wyrażeń regularnych z odpowiedzi Stevehy :

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

Oto niektóre inne odpowiedzi, które zostały opublikowane, i dane wejściowe, dla których nie działają zgodnie z oczekiwaniami, jeśli używamy definicji słowa będącego początkiem zdania lub czegokolwiek po spacji:

  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"      

użycie '' do podziału naprawi drugie wyjście, ale capwords () nadal nie będzie działać dla pierwszego

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

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

Uważaj na wiele pustych miejsc

  return ' '.join(w[0].upper() + w[1:] for w in s.split())
# Undesired outputs:
"foo    bar" => "Foo Bar"                 
aljgom
źródło
+1 za kompleksowe podsumowanie. Szukam sposobu na pisanie wielkimi literami po słowie (nie każdym słowie). Czy możesz uzupełnić swoją odpowiedź, która to pokazuje? Np. lower 123 upperPowinien powrócić lower 123 Upper, gdzie upperlitera jest pisana wielkimi literami, ponieważ następuje po niej liczba. Wiem, że wykracza to poza zakres pytania PO, ale stanowi miły dodatek do już i tak obszernej odpowiedzi. Z góry dziękuję.
ProGrammer,
W takim przypadku możesz zmodyfikować niektóre z powyższych metod, aby dostosować je do swoich potrzeb. Nie dodałbym tego jednak jako części odpowiedzi, ponieważ nie tego szuka większość ludzi. Użyłbym do tego wersji wyrażenia regularnego i używałbym "([0-9]+)(\s+.)"zamiast tego "(^|\s)(\S)"(dopasuj jedną lub więcej liczb, a następnie jedną lub więcej spacji i dowolne "([0-9]+)(\s*.)"znaki po ), lub jeśli chcesz wstawić znak po „zerach lub więcej” spacji po liczba
aljgom
Z pewnością przyjrzę się temu, co sprawiło, że pomyślałem o innym specjalnym przypadku: Jak zmodyfikowałbyś powyższe fragmenty, aby pobrać ciąg znaków, np. WW1 - the great warI wyjście WW1 - The Great Warzamiast Ww1 .... Widzisz problem ze skrótami? Czy byłbyś skłonny dodać coś, co pokazuje ten przypadek? Zastanawiam się nad tym od dłuższego czasu i nie mogę wymyślić sposobu, aby to zrobić.
ProGrammer
Pierwsze sposoby podane powyżej nie zmieniają listów, które zostały już aktywowane w ciągu wejściowego, więc WW1będzie odtwarzany jakoWW1
aljgom
15

Wersja @jibberia gotowa do skopiowania i wklejenia:

def capitalize(line):
    return ' '.join(s[:1].upper() + s[1:] for s in line.split(' '))
Konstantin Spirin
źródło
2
Nie trzeba budować listy. str.joinakceptuje generatory.
warvariuc
@warvariuc jak zmieniłbyś ten kod, aby wykorzystać generatory?
Konstantin Spirin
1
Po prostu usuń nawiasy kwadratowe, tak jak tutaj
warvariuc
1
Chociaż @warvariuc doskonale nadaje się do wspominania, że joinakceptuje generacje, w str.joinszczególności szczególnie preferowane jest używanie listowania . Wynika to z tego, że joiniteruje się dwa razy w stosunku do argumentu, a zatem szybsze jest dostarczenie gotowej listy niż generatora.
Bhargav Rao
1
@BhargavRao, dlaczego str.jointrzeba powtarzać dwukrotnie argument? Właśnie sprawdziłem - nie ma. Jednak w przypadku małych sekwencji zrozumienie listy jest rzeczywiście szybsze.
warvariuc
12

Dlaczego komplikujesz swoje życie połączeniami i pętlami, gdy rozwiązanie jest proste i bezpieczne?

Po prostu zrób to:

string = "the brown fox"
string[0].upper()+string[1:]
Brad Larson
źródło
2
Ponieważ może być kilka słów.
Arnaud,
1
Tak, ale często chcę tylko wielką literę. To jest na to sposób.
Deleet,
1
Czy nie używałbyś wtedy "the brown fox".capitalize()?
luckydonald
2
@luckydonald Bo może nie chcę, aby włączyć 'this is John'się 'This is john'.
janek37 11.04.17
Nie jest lepszym sposobem na zrobienie tego po prostu string.capitalize()(zasadniczo echo @luckydonald)
Hassan Baig
10

Jeśli str.title () nie działa dla Ciebie, wykonaj wielkie litery sam.

  1. Podziel ciąg na listę słów
  2. Wielką literą każdego słowa jest wielkie litery
  3. Połącz słowa w jeden ciąg

Jednowarstwowy:

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

Jasny przykład:

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)
dżibberia
źródło
1
Jednym z punktów zainteresowania tego rozwiązania jest utrata jakichkolwiek specjalnych białych znaków. Może nie być ważne w zależności od kontekstu.
mklauber
8

Jeśli tylko chcesz pierwszą literę:

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

Ale wielkie litery każdego słowa:

>>> 'hello world'.title()
'Hello World'
Zahran
źródło
Uważaj, bo 'hello New York'.capitalize()to'Hello new york'
user2314737
5

Pusty ciąg wywoła błąd, jeśli uzyskasz dostęp do [1:], dlatego użyłbym:

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

tylko wielką pierwszą literą.

Wim Feijen
źródło
Czy nie po to str.capitalizejest?
Eugene Pakhomov
4
@Eugene, tak, ale niestety, wielkie litery pisane wielką literą wszystkie inne litery, co może nie być pożądane. : /
Wim Feijen,
return title[:1].upper() + title[1:]będzie również dbać o ten problem, ponieważ krojenie pusty łańcuch tak dałoby 2 pustych strun, połączonych ze sobą zrobić pusty ciąg znaków, który jest zwracany
aljgom
3

Jak zauważył Mark, powinieneś użyć .title():

"MyAwesomeString".title()

Jednak jeśli chcesz zrobić pierwszą literę w szablonie django , możesz użyć tego:

{{ "MyAwesomeString"|title }}

lub używając zmiennej:

{{ myvar|title }}
chuckfinley
źródło
3

Sugerowana metoda str.title () nie działa we wszystkich przypadkach. Na przykład:

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

zamiast "A B 3c".

Myślę, że lepiej zrobić coś takiego:

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
źródło
1
jednak błąd może wystąpić, jeśli liczba odstępów między nimi nie jest 1. Dla odniesienia: problem z hackerem
Divakar Rajesh
3

Chociaż wszystkie odpowiedzi są już zadowalające, ale postaram się objąć 2 dodatkowe przypadki wraz ze wszystkimi poprzednimi przypadkami.

jeśli spacje nie są jednolite i chcesz zachować to samo

string = hello    world i  am    here.

jeśli cały ciąg nie zaczyna się od alfabetu

string = 1 w 2 r 3g

Tutaj możesz tego użyć

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

to ci da

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

Mam nadzieję, że to nie jest zbędne.

Amit Gupta
źródło
2
Dziękujemy za podkreślenie przypadku niejednorodnych przestrzeni. Niektóre powyższe odpowiedzi używają s.split () zamiast s.split (''). Ważne jest, aby pamiętać, że w przypadku niejednorodnych przestrzeni użycie s.split ('') zapewni utrzymanie niejednorodnych przestrzeni!
Jeszcze
To doskonale działa w przypadku słów o nierównych spacjach lub słów zaczynających się od cyfr. Dzięki :)
Amresh Giri
2

Aby używać wielkich słów ...

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

@ Gary02127 komentarz, poniżej tytuł pracy rozwiązania z apostrofem

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))
Czołg Tejas
źródło
Użycie istniejącej funkcji daje szybkie wykonanie w Pythonie.
Tejas Tank
Nie lubię tytułu (), ponieważ nie obsługuje apostrofów. „Nie mogę powiedzieć” .title () daje „I Can'T Say”
Gary02127,
@ Gary02127 Mam zaktualizowaną odpowiedź, proszę spojrzeć, działał również idealnie z domeną problemu
Tejas Tank
1

Nie zapomnij o zachowaniu białej przestrzeni. Jeśli chcesz przetworzyć, 'fred flinstone'a 'Fred Flinstone'zamiast tego 'Fred Flinstone'dostajesz, uszkodziłeś swoją białą przestrzeń. Niektóre z powyższych rozwiązań utracą białe miejsca. Oto rozwiązanie, które jest dobre dla Python 2 i 3 i pozwala zachować białe znaki.

def propercase(s):
    return ''.join(map(''.capitalize, re.split(r'(\s+)', s)))
Gary02127
źródło
0

Szybka funkcja działała w Pythonie 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
źródło
0

Łańcuch należy pisać wielkimi niejednolitymi spacjami

Rozumiem, że to stare pytanie i prawdopodobnie odpowiedzi zostały prawie wyrzucone z równowagi, ale chciałbym dodać do punktu niejednolitych przestrzeni @Amit Gupta. Z pierwotnego pytania chcielibyśmy używać każdego słowa w ciągu s = 'the brown fox'. Co jeśli ciąg miał s = 'the brown fox'niejednolite spacje.

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
źródło
.. kod nie kompensuje tabulacji, jeśli nie ma białych znaków między brązem a lisem ;-)
ZF007
-1

** W przypadku, gdy chcesz zmniejszyć rozmiar **

 #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
źródło
-2

Naprawdę podoba mi się ta odpowiedź:

Wersja @jibberia gotowa do skopiowania i wklejenia:

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

Ale niektóre wiersze, które wysyłałem, oddzielały puste znaki, które powodowały błędy podczas próby wykonania s [1:]. Prawdopodobnie jest na to lepszy sposób, ale musiałem dodać if len (s)> 0, jak w

return ' '.join([s[0].upper() + s[1:] for s in line.split(' ') if len(s)>0])
użytkownik1475777
źródło
2
To jest zbyt skomplikowane, czy możesz nawet sprawdzić długość ?! nieskuteczny.