Làm thế nào để viết hoa chữ cái đầu tiên của mỗi từ trong một chuỗi?


588
s = 'the brown fox'

... làm gì đó ở đây ...

s nên là :

'The Brown Fox'

Cách dễ nhất để làm điều này là gì?

Câu trả lời:


990

Các .title()phương pháp của một chuỗi (hoặc ASCII hoặc Unicode là tốt) thực hiện điều này:

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

Tuy nhiên, xem ra các chuỗi có dấu nháy đơn, như đã lưu ý trong tài liệu.

Thuật toán sử dụng một định nghĩa độc lập với ngôn ngữ đơn giản của một từ là các nhóm chữ cái liên tiếp. Định nghĩa này hoạt động trong nhiều ngữ cảnh nhưng điều đó có nghĩa là dấu nháy đơn trong các cơn co thắt và sở hữu tạo thành ranh giới từ, có thể không phải là kết quả mong muốn:

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

56
Tôi tránh vấn đề sở hữu với một cái gì đó như" ".join(w.capitalize() for w in s.split())
mehtunguh

3
điều này không an toàn cho hầu hết các chuỗi bởi vì mọi từ thậm chí sở hữu đều được đặt phía trên.

10
Có một vấn đề với chuỗi.title (). Khi bạn sử dụng, ví dụ, "e g 3b"kết quả mong muốn sẽ là "E G 3b". Tuy nhiên, "e g 3b".title()trả lại "E G 3B".
Sören

7
Hãy nhớ rằng điều này cũng sẽ gây ra điều này:In [2]: 'tEst'.title() Out[2]: 'Test'
Jonas Libbrecht

4
Câu trả lời tuyệt vời và các bình luận nhấn mạnh rằng trong python không phải mọi thứ đều hoạt động theo cách bạn cần, nhưng luôn có những cách thuận tiện để làm cho nó trở nên như vậy. Cách thuận tiện nhất là thường nhập một thư viện được xây dựng có mục đích, chẳng hạn như python-titlecase
Aaron3468 22/03/18

189

Các .title()phương pháp không thể làm việc tốt,

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

Hãy thử string.capwords()phương pháp,

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

Từ các tài liệu python trên capwords :

Phân tách đối số thành các từ bằng cách sử dụng str.split (), viết hoa mỗi từ bằng str.capitalize () và nối các từ viết hoa bằng str.join (). Nếu sep đối số thứ hai tùy chọn không có hoặc Không có, các ký tự khoảng trắng được thay thế bằng một khoảng trắng và khoảng trắng ở đầu và cuối được loại bỏ, nếu không thì sep được sử dụng để phân tách và nối các từ.


2
Capwords vẫn còn thiếu và không xử lý một cái gì đó như "There once was a string with an 'that had words right after it and then closed'". Với ví dụ này, tất cả các thế giới ngoại trừ thatđược viết hoa như mong đợi. Kết quả là"There Once Was A String With An 'that Had Words Right After It And Then Closed'"
devonbleibtrey

Tuy nhiên, điều này hoạt động tốt hơn so title()với các tình huống bình thường. Trong tình huống của tôi, title()trả về một đầu ra xấu cho các tên có dấu hoặc dieresis, trong khi capwords()xử lý nó một cách chính xác.
hoccros

1
Tốt, nhưng nó vẫn làm rối tung sự khác biệt "Anh / Anh"
Jonath P

1
@Chen Houwu, Uk / UK là một ví dụ hoàn hảo. Làm thế nào người ta có thể ngăn Python hạ thấp các chữ in hoa hiện có bằng một phương thức tương tự?
h0r53

105

Chỉ vì điều này là thú vị đối với tôi, đây là hai giải pháp nữa.

Chia thành các từ, giới hạn ban đầu từng từ trong các nhóm được phân chia và tham gia lại. Điều này sẽ thay đổi khoảng trắng phân tách các từ thành một khoảng trắng duy nhất, bất kể đó là gì.

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

EDIT: Tôi không nhớ những gì tôi đã nghĩ lại khi tôi viết đoạn mã trên, nhưng không cần phải xây dựng một danh sách rõ ràng; chúng ta có thể sử dụng một biểu thức tạo để làm điều đó trong thời trang lười biếng. Vì vậy, đây là một giải pháp tốt hơn:

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

Sử dụng một biểu thức chính quy để khớp với phần đầu của chuỗi hoặc các từ phân cách khoảng trắng, cộng với một ký tự không phải khoảng trắng; sử dụng dấu ngoặc đơn để đánh dấu "nhóm khớp". Viết hàm lấy một đối tượng khớp và trả về nhóm đối sánh khoảng trắng không thay đổi và nhóm khớp ký tự không phải khoảng trắng trong chữ hoa. Sau đó sử dụng re.sub()để thay thế các mẫu. Cái này không có vấn đề về dấu câu của giải pháp đầu tiên, nó cũng không làm lại khoảng trắng như giải pháp đầu tiên của tôi. Điều này tạo ra kết quả tốt nhất.

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"

Tôi rất vui vì tôi đã nghiên cứu câu trả lời này. Tôi không có ý tưởng re.sub()có thể có một chức năng! Bạn có thể thực hiện xử lý không cần thiết bên trong re.sub()để tạo ra kết quả cuối cùng!


1
+1 cho giải pháp sử dụng lát. Tôi cần một cái gì đó viết hoa chữ cái đầu tiên mà không thay đổi cách viết hoa của các từ còn lại (ví dụ Foo trở thành foo, nhưng FOO trở thành fOO). Điều này là hoàn hảo.
TomNysetvold

1
viết hoa trả về ký tự đầu tiên được viết hoa và phần còn lại
hạ thấp

@Vanuan, bạn nói đúng! Mô tả chuỗi doc làm tôi nghĩ rằng tất cả những gì nó đã làm là viết hoa chữ cái đầu tiên, nhưng bạn đã đúng về những gì nó thực sự làm. Tôi sẽ chỉnh sửa câu trả lời. Cảm ơn bạn đã đứng đầu.
steveha

Điều này dường như là những gì string.capwordslàm, theo tài liệu trong câu trả lời của Chen Houwu.
Adrian Keister

1
Một cái gì đó cần lưu ý trong câu trả lời ở trên, thay vì sử dụng s.split (), tôi nghĩ tốt hơn là sử dụng s.split (''). Điều này là do trong trường hợp chuỗi có một số khoảng trắng kép và bạn muốn duy trì các khoảng trắng kép đó khi tham gia, s.plit ('') sẽ giúp bạn duy trì khoảng trắng trong khi s.split () sẽ không
manpikin

21

Dưới đây là tóm tắt về các cách khác nhau để thực hiện, chúng sẽ hoạt động cho tất cả các đầu vào sau:

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

- Giải pháp đơn giản nhất là chia câu thành các từ và viết hoa chữ cái đầu tiên sau đó nối lại với nhau:

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

- Nếu trước tiên bạn không muốn tách chuỗi đầu vào thành các từ và sử dụng các trình tạo ưa thích:

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

- Hoặc không nhập itertools:

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

- Hoặc bạn có thể sử dụng các biểu thức thông thường, từ câu trả lời của 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)

Bây giờ, đây là một số câu trả lời khác đã được đăng và đầu vào mà chúng không hoạt động như mong đợi nếu chúng ta sử dụng định nghĩa của một từ là bắt đầu câu hoặc bất cứ điều gì sau một khoảng trắng:

  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"      

sử dụng '' cho phần tách sẽ khắc phục đầu ra thứ hai, nhưng capwords () vẫn không hoạt động cho lần đầu tiên

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

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

Cẩn thận với nhiều chỗ trống

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

+1 cho một bản tóm tắt toàn diện. Tôi đang tìm kiếm một cách chỉ viết hoa một từ theo sau một số (không phải mỗi từ). Bạn có thể bổ sung cho câu trả lời của bạn chứng minh điều này? Ví dụ, lower 123 uppernên trả về lower 123 Upper, trong đó upperchữ viết hoa theo sau một số. Tôi biết nó vượt ra ngoài phạm vi câu hỏi của OP nhưng là một tiện ích bổ sung tuyệt vời cho câu trả lời đã được mở rộng của bạn. Cảm ơn trước.
ProGrammer

Bạn có thể sửa đổi một số phương pháp trên cho phù hợp với nhu cầu của bạn trong trường hợp này. Tuy nhiên, tôi sẽ không thêm nó vào như một phần của câu trả lời vì đó không phải là điều mà hầu hết mọi người đang tìm kiếm. Tôi sẽ sử dụng phiên bản regex cho nó và sử dụng "([0-9]+)(\s+.)"thay vì "(^|\s)(\S)"(khớp một hoặc nhiều số, theo sau là một hoặc nhiều khoảng trắng và bất kỳ ký tự nào sau) hoặc "([0-9]+)(\s*.)"nếu bạn muốn viết hoa ký tự sau khoảng trắng '0 hoặc nhiều hơn' sau dấu cách số
aljeim

Tôi chắc chắn sẽ xem xét nó, điều đó khiến tôi suy nghĩ về một trường hợp đặc biệt khác: Làm thế nào bạn sửa đổi các đoạn trích ở trên để lấy một chuỗi, ví dụ WW1 - the great warvà đầu ra WW1 - The Great Warthay vì Ww1 .... Xem vấn đề với chữ viết tắt? Bạn có sẵn sàng để thêm một cái gì đó chứng minh trường hợp này? Tôi đã tự hỏi về điều này trong một thời gian và không thể nghĩ ra cách nào để làm điều đó.
ProGrammer

Những cách đầu tiên được nêu ở trên không thay đổi các chữ cái đã được viết hoa trong chuỗi đầu vào, do đó, WW1sẽ xuất ra dưới dạngWW1
aljeim

15

Phiên bản sao chép-dán sẵn sàng của @jibberia anwser:

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

2
Không cần phải xây dựng một danh sách. str.joinchấp nhận máy phát điện.
warvariuc

@warvariuc bạn sẽ thay đổi mã này thành đòn bẩy như thế nào?
Konstantin Spirin

1
Chỉ cần xóa dấu ngoặc vuông, giống như được thực hiện ở đây
warvariuc

1
Mặc dù @warvariuc là hoàn hảo khi đề cập đến việc joinchấp nhận gen exp, nhưng trong trường hợp str.joinđặc biệt, nó thường được ưu tiên sử dụng cách hiểu danh sách. Điều này là do joinlặp lại hai lần so với đối số và do đó nhanh hơn để cung cấp danh sách sẵn sàng hơn là một trình tạo.
Bhargav Rao

1
@BhargavRao tại sao str.joincần phải lặp lại hai lần so với đối số? Tôi chỉ kiểm tra - không. Mặc dù đối với trình tự nhỏ, việc hiểu danh sách thực sự nhanh hơn.
warvariuc

12

Tại sao bạn làm phức tạp cuộc sống của bạn với tham gia và cho các vòng lặp khi giải pháp đơn giản và an toàn ??

Chỉ cần làm điều này:

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

2
Bởi vì có thể có một vài từ.
Arnaud

1
Có, nhưng thường tôi chỉ muốn viết hoa chữ cái đầu tiên. Đây là một cách để làm điều đó.
Deleet

1
Bạn sẽ không sử dụng "the brown fox".capitalize()chứ?
luckydonald

2
@luckydonald Vì có lẽ tôi không muốn biến 'this is John'thành 'This is john'.
janek37

Không phải là cách tốt hơn để làm điều này đơn giản string.capitalize()(về cơ bản là tiếng vang @luckydonald)
Hassan Baig

10

Nếu str.title () không phù hợp với bạn, hãy tự viết hoa.

  1. Chia chuỗi thành một danh sách các từ
  2. Viết hoa chữ cái đầu tiên của mỗi từ
  3. Nối các từ thành một chuỗi

Lót:

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

Ví dụ rõ ràng:

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
Một điểm đáng chú ý với giải pháp này là bạn mất bất kỳ khoảng trắng đặc biệt nào. Có thể không quan trọng tùy thuộc vào bối cảnh.
mklauber

8

Nếu chỉ bạn muốn chữ cái đầu tiên:

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

Nhưng để viết hoa từng chữ:

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

Cẩn thận vì 'hello New York'.capitalize()'Hello new york'
user2314737

5

Một chuỗi trống sẽ phát sinh Lỗi nếu bạn truy cập [1:], do đó tôi sẽ sử dụng:

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

để viết hoa chữ cái đầu tiên


Đó không phải là những gì str.capitalizecho?
Eugene Pakhomov

4
@Eugene, có nhưng thật không may, viết hoa chữ thường tất cả các chữ cái khác có thể không mong muốn. : /
Wim Feijen

return title[:1].upper() + title[1:]cũng sẽ giải quyết vấn đề đó vì việc cắt chuỗi rỗng như thế sẽ tạo ra 2 chuỗi trống, kết hợp với nhau tạo thành một chuỗi trống được trả về
aljeim

3

Như Mark đã chỉ ra, bạn nên sử dụng .title():

"MyAwesomeString".title()

Tuy nhiên, nếu muốn tạo chữ hoa đầu tiên trong mẫu django , bạn có thể sử dụng:

{{ "MyAwesomeString"|title }}

hoặc sử dụng một biến:

{{ myvar|title }}

3

Phương thức được đề xuất str.title () không hoạt động trong mọi trường hợp. Ví dụ:

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

thay vì "A B 3c".

Tôi nghĩ, tốt hơn là làm một cái gì đó như thế này:

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
tuy nhiên lỗi có thể phát sinh nếu số lượng khoảng cách phân tách chúng không phải là 1. Để tham khảo: vấn đề hackerrank
Divakar Rajesh

3

Mặc dù tất cả các câu trả lời đã thỏa đáng nhưng tôi sẽ cố gắng bao gồm 2 trường hợp bổ sung cùng với tất cả các trường hợp trước đó.

nếu các không gian không đồng nhất và bạn muốn duy trì như cũ

string = hello    world i  am    here.

nếu tất cả các chuỗi không bắt đầu từ bảng chữ cái

string = 1 w 2 r 3g

Ở đây bạn có thể sử dụng này

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

cái này sẽ cho bạn

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

Tôi hy vọng điều này không dư thừa.


2
Cảm ơn đã làm nổi bật trường hợp không gian không đồng đều. Một số câu trả lời ở trên sử dụng s.split () thay vì s.split (''). Điều quan trọng cần lưu ý là đối với các không gian không đồng nhất, sử dụng s.split ('') sẽ đảm bảo rằng các không gian không đồng nhất được duy trì! Cảm ơn một lần nữa
manpikin

Điều này hoàn toàn hoạt động cho các từ có không gian không đồng đều hoặc các từ bắt đầu bằng một số chữ số. Cảm ơn :)
Amresh Giri

2

Để viết hoa ...

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

@ Gary02127 bình luận, bên dưới tiêu đề công việc giải pháp với dấu nháy đơn

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

Sử dụng chức năng hiện có để thực hiện nhanh chóng trong python.
Xe tăng Tejas

Tôi không thích tiêu đề (), vì nó không xử lý dấu nháy đơn. "Tôi không thể nói" .title () đưa ra "Tôi không thể nói"
Gary02127

@ Gary02127 tôi đã cập nhật câu trả lời, xin vui lòng có một cái nhìn, hoàn hảo làm việc với miền vấn đề của bạn quá
Tejas Bể

1

Đừng bỏ qua việc bảo tồn không gian màu trắng. Nếu bạn muốn xử lý 'fred flinstone''Fred Flinstone'thay vào đó 'Fred Flinstone', bạn đã làm hỏng khoảng trắng của mình. Một số giải pháp trên sẽ mất khoảng trắng. Đây là một giải pháp tốt cho Python 2 và 3 và duy trì khoảng trắng.

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

0

Một chức năng nhanh đã làm việc cho 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

Viết hoa chuỗi với không gian không đồng nhất

Chà, tôi hiểu đây là một câu hỏi cũ và có lẽ câu trả lời gần như đã cạn kiệt, nhưng tôi muốn thêm vào điểm không gian không đồng nhất của @Amit Gupta. Từ câu hỏi ban đầu, chúng tôi muốn viết hoa từng từ trong chuỗi s = 'the brown fox'. Điều gì xảy ra nếu chuỗi là s = 'the brown fox'không gian không đồng nhất.

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)

.. mã của bạn không thể bù cho các tab nếu nó không có khoảng trắng giữa màu nâu và con cáo ;-)
ZF007

-1

** Trong trường hợp bạn muốn giảm kích thước **

 #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

Tôi thực sự thích câu trả lời này:

Phiên bản sao chép-dán sẵn sàng của @jibberia anwser:

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

Nhưng một số dòng mà tôi đã gửi đã tách ra một số ký tự '' trống gây ra lỗi khi cố gắng thực hiện s [1:]. Có lẽ có một cách tốt hơn để làm điều này, nhưng tôi đã phải thêm vào nếu len (s)> 0, như trong

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

2
Điều này quá phức tạp, thậm chí bạn còn phải kiểm tra độ dài?! không hiệu quả.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.