Titolo contenente una stringa con eccezioni


87

C'è un modo standard in Python per Titlecase una stringa (vale a dire le parole iniziano con caratteri maiuscoli, tutti i caratteri con carter rimanenti hanno minuscolo) ma che lasciano articoli come and, ine ofcaratteri minuscoli?

Risposte:


151

Ci sono alcuni problemi con questo. Se utilizzi la divisione e l'unione, alcuni caratteri di spazio vuoto verranno ignorati. I metodi incorporati in maiuscolo e titolo non ignorano gli spazi vuoti.

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

Se una frase inizia con un articolo, non vuoi che la prima parola di un titolo sia in minuscolo.

Tenendo a mente questi:

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

Perché è renecessario? C'è una "".splitfunzione che fa lo stesso.
wizzwizz4

1
@ wizzwizz4: str.splitnon considera gli spazi contigui. re.splitconserva gli spazi. Quindi, questa funzione non consuma spazi.
dheerosaur

@dheerosaur ho pensato che "".split()non li considerasse ma lo ha "".split(" ")fatto.
wizzwizz4

Il tuo snippet non funzionerà correttamente per il title_except('a whim of aN elephant', articles)caso. È possibile utilizzare la word.lower() in exceptionscondizione di filtro per risolverlo.
Dariusz Walczak

@dheerosaur Sto cercando un modo per scrivere in maiuscolo qualsiasi parola che segue non solo un articolo ma anche un numero. Potresti aggiungere alla tua risposta che lo dimostri? Ad esempio, 2001 a Space Odysseydovrebbe restituire 2001 A Space Odyssey, dove aè in maiuscolo come segue un numero. Grazie in anticipo.
ProGrammer

53

Usa il modulo titlecase.py ! Funziona solo per l'inglese.

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

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


1
Il modulo titlecase non funziona se la stringa che stai convertendo contiene un numero ovunque al suo interno.
Troy

1
@ Troy sembra che il problema con il numero sia stato risolto o non ho colpito il tuo caso limite. Es: titlecase ('one 4 two') -> 'One 4 Two'. Ora titlecase ('1one') -> '1one', ma '1one'.title () ->' 1One '. sebbene questo caso successivo sia un caso limite e non sono sicuro che "1One" sia il titolo corretto. Inoltre, non sono abbastanza preoccupato da afferrare il mio libro di grammatica.
brent.payne

Non funzionerà nel caso di "321 A BROADWAY STREET" dove ottengo "321 a Broadway Street". Utilizzando la soluzione proposta da dheerosaur sopra produce "321 A Broadway Street".
MoreScratch

Bello anche, lascia intatti gli acronimi nel titolo. "sviluppo di TIaSR innovativo" diventa "Sviluppo di TIaSR innovativo".
Matthias Arras l'

22

Esistono questi metodi:

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

Non esiste un'opzione articolo in minuscolo. Dovresti codificarlo tu stesso, probabilmente utilizzando un elenco di articoli che desideri ridurre.


articoli in minuscolo titlecase.py.
TRS-80

14

Stuart Colville ha realizzato un port in Python di uno script Perl scritto da John Gruber per convertire le stringhe in maiuscole e minuscole, ma evita di usare le maiuscole in base alle regole del Manuale di stile del New York Times, oltre a soddisfare diversi casi speciali.

Alcune delle abilità di questi script:

  • mettono in maiuscolo le piccole parole come if, in, of, on , ecc., ma le rimuoveranno se sono erroneamente capitalizzate nell'input.

  • gli script presumono che le parole con lettere maiuscole diverse dal primo carattere siano già correttamente maiuscole. Ciò significa che lasceranno una parola come "iTunes" da sola, piuttosto che trasformarla in "ITunes" o, peggio, "Itunes".

  • saltano le parole con i punti di linea; "Example.com" e "del.icio.us" rimarranno in minuscolo.

  • hanno hack hard-coded specificatamente per trattare casi strani, come "AT&T" e "Q&A", che contengono entrambe piccole parole (at e a) che normalmente dovrebbero essere minuscole.

  • La prima e l'ultima parola del titolo sono sempre in maiuscolo, quindi input come "Niente di cui aver paura" verranno trasformati in "Niente di cui aver paura".

  • Una piccola parola dopo i due punti sarà in maiuscolo.

Puoi scaricarlo qui .


4
capitalize (word)

Questo dovrebbe bastare. Lo capisco diversamente.

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

Ok come detto nella risposta sopra, devi fare una maiuscola personalizzata:

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

Questo produce

I am a Foobar Bazbar

Non è quello che voglio. Voglio ricevere "Sono un Foobar Bazbar"
yassin

@ Yassin Ezbakhe: Ho modificato la mia risposta, dovrebbe funzionare per te. L'elenco degli articoli può essere facilmente rimosso da qualsiasi dizionario
pyfunc

2

Il metodo del titolo di Python 2.7 ha un difetto.

value.title()

restituirà Carpenter ' S Assistant quando il valore è Carpenter' 's Assistant

La soluzione migliore è probabilmente quella di @BioGeek usando titlecase di Stuart Colville. Che è la stessa soluzione proposta da @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
"""

Il titolo inizia con una parola in maiuscolo e non corrisponde all'articolo.


1

One-liner utilizzando la comprensione delle liste e l'operatore ternario

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)

Abbattersi:

for word in "Wow, a python one liner for titles".split(" ") Divide la stringa in un elenco e avvia un ciclo for (nella comprensione della lista)

word.title() if word not in "the a on in of an" else word utilizza il metodo nativo title() per titolo la stringa se non è un articolo

" ".join unisce gli elementi della lista con un separatore di (spazio)


0

Un caso importante che non viene considerato sono gli acronimi (la soluzione python-titlecase può gestire gli acronimi se li fornisci esplicitamente come eccezioni). Preferisco invece evitare semplicemente il down-case. Con questo approccio, gli acronimi che sono già maiuscoli rimangono in maiuscolo. Il codice seguente è una modifica di quello originariamente fornito da 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))

Quando viene eseguito, produce quanto segue:

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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.