Viết hoa tiêu đề một chuỗi có ngoại lệ


87

Có cách nào tiêu chuẩn trong Python để titlecase một chuỗi (tức là từ bắt đầu với ký tự chữ hoa, tất cả các nhân vật cased còn lại có chữ thường) nhưng điều để lại như and, inoflowercased?

Câu trả lời:


151

Có một số vấn đề với điều này. Nếu bạn sử dụng tách và nối, một số ký tự khoảng trắng sẽ bị bỏ qua. Các phương thức viết hoa và tiêu đề cài sẵn không bỏ qua khoảng trắng.

>>> 'There     is a way'.title()
'There     Is A Way'

Nếu một câu bắt đầu bằng một bài báo, bạn không muốn từ đầu tiên của tiêu đề ở dạng chữ thường.

Hãy ghi nhớ những điều này:

import re 
def title_except(s, exceptions):
    word_list = re.split(' ', s)       # re.split behaves as expected
    final = [word_list[0].capitalize()]
    for word in word_list[1:]:
        final.append(word if word in exceptions else word.capitalize())
    return " ".join(final)

articles = ['a', 'an', 'of', 'the', 'is']
print title_except('there is a    way', articles)
# There is a    Way
print title_except('a whim   of an elephant', articles)
# A Whim   of an Elephant

Tại sao recần thiết? Có một "".splitchức năng hoạt động tương tự.
wizzwizz

1
@ wizzwizz4: str.splitkhông xem xét các không gian liền kề. re.splitgiữ lại các khoảng trống. Vì vậy, hàm này không chiếm bất kỳ khoảng trắng nào.
dheerosaur

@dheerosaur Tôi đã nghĩ rằng "".split()không xem xét họ nhưng "".split(" ")đã làm.
wizzwizz

Đoạn mã của bạn sẽ không hoạt động chính xác cho từng title_except('a whim of aN elephant', articles)trường hợp. Bạn có thể sử dụng word.lower() in exceptionsđiều kiện lọc để khắc phục nó.
Dariusz Walczak

@dheerosaur Tôi đang tìm cách viết hoa bất kỳ từ nào theo sau không chỉ một bài báo mà còn cả một số. Bạn có thể bổ sung cho câu trả lời của mình để chứng minh điều này không? Ví dụ: 2001 a Space Odysseyshould return 2001 A Space Odyssey, trong đó ký tự ađược viết hoa theo sau một số. Cảm ơn trước.
ProGrammer

53

Sử dụng mô-đun titlecase.py ! Chỉ hoạt động cho tiếng Anh.

>>> from titlecase import titlecase
>>> titlecase('i am a foobar bazbar')
'I Am a Foobar Bazbar'

GitHub: https://github.com/ppannuto/python-titlecase


1
Mô-đun titlecase không hoạt động nếu chuỗi bạn đang chuyển đổi chứa một số ở bất kỳ đâu trong đó.
Troy

1
@Troy có vẻ như sự cố số đã được khắc phục, hoặc tôi không gặp phải trường hợp lợi hại của bạn. Ví dụ: titlecase ('một 4 hai') -> 'Một 4 Hai'. Bây giờ titlecase ('1one') -> '1one', nhưng '1one'.title () ->' 1One '. mặc dù trường hợp sau này là một trường hợp cạnh và tôi không chắc '1One' là cách đặt tiêu đề chính xác. Tôi cũng không đủ quan tâm để lấy cuốn sách ngữ pháp của mình.
brent.payne

Sẽ không hoạt động trong trường hợp "321 A BROADWAY STREET" nơi tôi nhận được "321 a Broadway Street". Sử dụng giải pháp do dheerosaur đề xuất ở trên tạo ra "321 A Broadway Street".
MoreScratch

Cũng tốt, nó để lại các từ viết tắt trong tiêu đề không bị đụng chạm. 'phát triển TIaSR sáng tạo' trở thành 'Phát triển TIaSR sáng tạo'.
Matthias Arras

22

Có những phương pháp sau:

>>> mytext = u'i am a foobar bazbar'
>>> print mytext.capitalize()
I am a foobar bazbar
>>> print mytext.title()
I Am A Foobar Bazbar

Không có tùy chọn bài viết viết thường. Bạn phải tự mình viết mã điều đó, có thể bằng cách sử dụng danh sách các bài báo bạn muốn hạ xuống.


titlecase.py bài viết viết thường.
TRS-80

14

Stuart Colville đã tạo một cổng Python của tập lệnh Perl do John Gruber viết để chuyển đổi các chuỗi thành chữ hoa tiêu đề nhưng tránh viết hoa các từ nhỏ dựa trên các quy tắc từ Sổ tay hướng dẫn về văn phong của Thời báo New York, cũng như phục vụ cho một số trường hợp đặc biệt.

Một số thông minh của các tập lệnh này:

  • chúng viết hoa các từ nhỏ như if, in, of, on , v.v., nhưng sẽ bỏ viết hoa nếu chúng được viết hoa sai trong đầu vào.

  • các tập lệnh giả định rằng các từ có chữ cái viết hoa khác với ký tự đầu tiên đã được viết hoa chính xác. Điều này có nghĩa là họ sẽ để lại một từ như “iTunes”, thay vì ghép nó thành “ITunes” hoặc tệ hơn là “Itunes”.

  • họ bỏ qua bất kỳ từ nào có dấu chấm dòng; “Example.com” và “del.icio.us” sẽ vẫn là chữ thường.

  • họ có các bản hack được mã hóa cứng đặc biệt để giải quyết các trường hợp kỳ quặc, như “AT&T” và “Q&A”, cả hai đều chứa các từ nhỏ (at và a) thường phải là chữ thường.

  • Từ đầu tiên và từ cuối cùng của tiêu đề luôn được viết hoa, vì vậy đầu vào như "Không có gì phải sợ" sẽ được chuyển thành "Không có gì phải sợ".

  • Một từ nhỏ sau dấu hai chấm sẽ được viết hoa.

Bạn có thể tải về tại đây .


4
capitalize (word)

Điều này nên làm. Tôi hiểu nó theo cách khác.

>>> mytext = u'i am a foobar bazbar'
>>> mytext.capitalize()
u'I am a foobar bazbar'
>>>

Như đã nói trong phần trả lời ở trên, bạn phải viết hoa tùy chỉnh:

mytext = u'i am a foobar bazbar '

def xcaptilize(word):
    skipList = ['a', 'an', 'the', 'am']
    if word not in skipList:
        return word.capitalize()
    return word

k = mytext.split(" ") 
l = map(xcaptilize, k)
print " ".join(l)   

Kết quả này

I am a Foobar Bazbar

Đó không phải là điều tôi muốn. Tôi muốn nhận "Tôi là Foobar Bazbar"
yassin

@Yassin Ezbakhe: Đã chỉnh sửa câu trả lời của tôi, điều này sẽ phù hợp với bạn. Danh sách các bài viết có thể dễ dàng nâng lên từ bất kỳ từ điển
pyfunc

2

Phương thức tiêu đề của Python 2.7 có một lỗ hổng trong đó.

value.title()

sẽ trở lại 'Carpenter S Trợ lý khi giá trị là Carpenter' s Assistant

Giải pháp tốt nhất có lẽ là giải pháp từ @BioGeek sử dụng tiêu đề từ Stuart Colville. Đó là giải pháp tương tự được đề xuất bởi @Etienne.


1
 not_these = ['a','the', 'of']
thestring = 'the secret of a disappointed programmer'
print ' '.join(word
               if word in not_these
               else word.title()
               for word in thestring.capitalize().split(' '))
"""Output:
The Secret of a Disappointed Programmer
"""

Tiêu đề bắt đầu bằng từ viết hoa và điều đó không khớp với bài viết.


1

Một lớp lót sử dụng tính năng hiểu danh sách và toán tử bậc ba

reslt = " ".join([word.title() if word not in "the a on in of an" else word for word in "Wow, a python one liner for titles".split(" ")])
print(reslt)

Phá vỡ:

for word in "Wow, a python one liner for titles".split(" ") Tách chuỗi thành một danh sách và bắt đầu một vòng lặp for (trong phần hiểu danh sách)

word.title() if word not in "the a on in of an" else wordsử dụng phương thức gốc title()để đặt tiêu đề cho chuỗi nếu nó không phải là một bài báo

" ".join tham gia các phần tử danh sách với một bộ tách là (khoảng trắng)


0

Một trường hợp quan trọng không được xem xét là từ viết tắt (giải pháp python-titlecase có thể xử lý các từ viết tắt nếu bạn cung cấp rõ ràng chúng dưới dạng ngoại lệ). Thay vào đó, tôi muốn đơn giản là tránh cách viết hoa. Với cách tiếp cận này, các từ viết tắt đã là chữ hoa vẫn ở dạng chữ hoa. Đoạn mã sau đây là một sửa đổi của mã được cung cấp ban đầu bởi dheerosaur.

# This is an attempt to provide an alternative to ''.title() that works with 
# acronyms.
# There are several tricky cases to worry about in typical order of importance:
# 0. Upper case first letter of each word that is not an 'minor' word.
# 1. Always upper case first word.
# 2. Do not down case acronyms
# 3. Quotes
# 4. Hyphenated words: drive-in
# 5. Titles within titles: 2001 A Space Odyssey
# 6. Maintain leading spacing
# 7. Maintain given spacing: This is a test.  This is only a test.

# The following code addresses 0-3 & 7.  It was felt that addressing the others 
# would add considerable complexity.


def titlecase(
    s,
    exceptions = (
        'and', 'or', 'nor', 'but', 'a', 'an', 'and', 'the', 'as', 'at', 'by',
        'for', 'in', 'of', 'on', 'per', 'to'
    )
):
    words = s.strip().split(' ')
        # split on single space to maintain word spacing
        # remove leading and trailing spaces -- needed for first word casing

    def upper(s):
        if s:
            if s[0] in '‘“"‛‟' + "'":
                return s[0] + upper(s[1:])
            return s[0].upper() + s[1:]
        return ''

    # always capitalize the first word
    first = upper(words[0])

    return ' '.join([first] + [
        word if word.lower() in exceptions else upper(word)
        for word in words[1:]
    ])


cases = '''
    CDC warns about "aggressive" rats as coronavirus shuts down restaurants
    L.A. County opens churches, stores, pools, drive-in theaters
    UConn senior accused of killing two men was looking for young woman
    Giant asteroid that killed the dinosaurs slammed into Earth at ‘deadliest possible angle,’ study reveals
    Maintain given spacing: This is a test.  This is only a test.
'''.strip().splitlines()

for case in cases:
    print(titlecase(case))

Khi chạy, nó tạo ra như sau:

CDC Warns About "Aggressive" Rats as Coronavirus Shuts Down Restaurants L.A. County Opens Churches, Stores, Pools, Drive-in Theaters
UConn Senior Accused of Killing Two Men Was Looking for Young Woman
Giant Asteroid That Killed the Dinosaurs Slammed Into Earth at ‘Deadliest Possible Angle,’ Study Reveals
Maintain Given Spacing: This Is a Test.  This Is Only a Test.
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.