Заголовок строки с исключениями


87

Есть стандартный способ в Python для titlecase строки (т.е. слова начинаются с прописными буквами, все остальные символы имеют обсаженные в нижнем регистр) , но оставив статьи , как and, inи ofстрочные?

Ответы:


151

С этим есть несколько проблем. Если вы используете разделение и соединение, некоторые символы пробела будут проигнорированы. Встроенные методы капитализации и заголовка не игнорируют пробелы.

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

Если предложение начинается со статьи, вы не хотите, чтобы первое слово заголовка было в нижнем регистре.

Имея это в виду:

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

Зачем это reнужно? Есть "".splitфункция, которая делает то же самое.
wizzwizz4

1
@ wizzwizz4: str.splitне учитывает смежные пробелы. re.splitсохраняет пробелы. Итак, эта функция не занимает места.
dheerosaur

@dheerosaur Я думал, что "".split()не считал их, но учел "".split(" ").
wizzwizz4

Ваш фрагмент не будет работать правильно для title_except('a whim of aN elephant', articles)case. Вы можете использовать word.lower() in exceptionsусловие фильтрации, чтобы исправить это.
Дариуш Вальчак

@dheerosaur Я ищу способ использовать заглавные буквы в любом слове, которое следует не только за статьей, но и за числом. Не могли бы вы сделать дополнение к своему ответу, демонстрирующее это? Например, 2001 a Space Odysseyдолжен вернуться 2001 A Space Odyssey, где после aчисла следует заглавная буква. Заранее спасибо.
ProGrammer 04

53

Используйте модуль titlecase.py ! Работает только на английском.

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

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


1
Модуль titlecase не работает, если строка, которую вы конвертируете, содержит где-либо число.
Troy

1
@Troy, похоже, проблема с числом исправлена, или я не попал в ваш крайний случай. Пример: titlecase ('один 4 два') -> 'Один 4 Два'. Теперь titlecase ('1one') -> '1one', но '1one'.title () ->' 1One '. хотя этот более поздний случай является крайним случаем, и я не уверен, что «1One» - правильное название. Я также не настолько обеспокоен, чтобы взять учебник по грамматике.
brent.payne

Не будет работать в случае "321 A BROADWAY STREET", где я получаю "321 a Broadway Street". Используя решение, предложенное выше диерозавром, получаем "321 A Broadway Street".
MoreScratch

Также приятно, что аббревиатуры в названии остаются нетронутыми. «Развитие инновационных ТИАСР» становится «Развитие инновационных ТИАСР».
Матиас Аррас,

22

Вот такие методы:

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

Вариантов артикля в нижнем регистре нет. Вам придется написать это самостоятельно, возможно, используя список статей, которые вы хотите сократить.


titlecase.py переводит статьи в нижний регистр.
TRS-80,

14

Стюарт Colville сделал порт Python из сценария Perl , написанной Джон Грубер , чтобы преобразовать строки в заголовке дела , но избегает спекулируя небольшие слова , основанные на правилах из New York Times Руководство по стилю, а также питания для нескольких частных случаев.

Некоторые из умений этих сценариев:

  • они пишут с заглавной буквы маленькие слова, такие как if, in, of, on и т. д., но не используют их, если они ошибочно написаны с заглавной буквы.

  • сценарии предполагают, что слова с заглавными буквами, кроме первого символа, уже правильно написаны с заглавной буквы. Это означает, что они оставят слово вроде «iTunes» в покое, а не превратят его в «ITunes» или, что еще хуже, «Itunes».

  • они пропускают любые слова с точками; «Example.com» и «del.icio.us» останутся строчными.

  • у них есть жестко запрограммированные хаки, специально предназначенные для работы со странными случаями, например «AT&T» и «Q&A», оба из которых содержат маленькие слова (at и a), которые обычно должны быть строчными.

  • Первое и последнее слово заголовка всегда пишутся с заглавной буквы, поэтому ввод, такой как «Нечего бояться», будет преобразован в «Нечего бояться».

  • Маленькое слово после двоеточия будет заглавным.

Вы можете скачать его здесь .


4
capitalize (word)

Это должно сработать. Я понимаю иначе.

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

Хорошо, как сказано в ответе выше, вы должны сделать настраиваемый регистр:

mytext = u'i am 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)   

Это выводит

I am a Foobar Bazbar

Я не этого хочу. Я хочу получить «Я Фубар Базбар»
Ясин

@ Ясин Эзбахе: Отредактировал мой ответ, это должно сработать для вас. Список статей легко взять из любого словаря
pyfunc

2

В методе заголовка Python 2.7 есть недостаток.

value.title()

вернет Carpenter ' S Assistant, если значение равно Carpenter' s Assistant

Лучшее решение, вероятно, от @BioGeek с использованием titlecase от Стюарта Колвилла. Это то же самое решение, которое предлагает @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
"""

Название начинается с заглавной буквы, что не соответствует статье.


1

Однострочный с использованием понимания списка и тернарного оператора

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)

Сломать:

for word in "Wow, a python one liner for titles".split(" ") Разбивает строку на список и запускает цикл for (в понимании списка)

word.title() if word not in "the a on in of an" else word использует собственный метод title() для заголовка строки, если это не статья

" ".join объединяет элементы списка с разделителем (пробел)


0

Один важный случай, который не рассматривается, - это аббревиатуры (решение python-titlecase может обрабатывать акронимы, если вы явно указываете их как исключения). Вместо этого я предпочитаю просто избегать погружения в корпус. При таком подходе аббревиатуры, уже написанные в верхнем регистре, остаются в верхнем регистре. Следующий код является модификацией кода, изначально предоставленного 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))

При запуске выдает следующее:

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.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.