Título de una cadena con excepciones

87

¿Hay una manera estándar de Python para TitleCase una cadena (es decir, las palabras comienzan con mayúsculas, todos los caracteres alfabéticos restantes tienen minúscula) pero los artículos que salen como and, iny ofen minúsculas?

yassin
fuente

Respuestas:

151

Hay algunos problemas con esto. Si usa dividir y unir, se ignorarán algunos espacios en blanco. Los métodos incorporados de capitalización y título no ignoran los espacios en blanco.

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

Si una oración comienza con un artículo, no desea que la primera palabra de un título esté en minúsculas.

Teniendo esto en cuenta:

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
dheerosaur
fuente
¿Por qué es renecesario? Hay una "".splitfunción que hace lo mismo.
wizzwizz4
1
@ wizzwizz4: str.splitno considera espacios contiguos. re.splitretiene espacios. Entonces, esta función no ocupa ningún espacio.
dheerosaur
@dheerosaur Pensé que "".split()no los tenía en cuenta, pero lo "".split(" ")hizo.
wizzwizz4
Su fragmento no funcionará correctamente para el title_except('a whim of aN elephant', articles)caso. Puede utilizar la word.lower() in exceptionscondición de filtrado para solucionarlo.
Dariusz Walczak
@dheerosaur Estoy buscando una manera de poner en mayúscula cualquier palabra que siga no solo a un artículo sino también a un número. ¿Podría agregar algo a su respuesta que demuestre esto? Por ejemplo, 2001 a Space Odysseydebería volver 2001 A Space Odyssey, donde ase escribe en mayúscula, ya que sigue a un número. Gracias por adelantado.
ProGrammer
53

¡Utilice el módulo titlecase.py ! Funciona solo para inglés.

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

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

Etienne
fuente
1
El módulo titlecase no funciona si la cadena que está convirtiendo contiene un número en cualquier lugar.
Troy
1
@Troy parece que el problema del número está solucionado, o no llegué a su caso límite. Ej: titlecase ('uno 4 dos') -> 'Uno 4 Dos'. Ahora titlecase ('1one') -> '1one', pero '1one'.title () ->' 1One '. aunque este último caso es un caso límite y no estoy seguro de que '1One' sea el título correcto. Tampoco estoy lo suficientemente preocupado como para agarrar mi libro de gramática.
brent.payne
No funcionará en el caso de "321 A BROADWAY STREET" donde obtengo "321 a Broadway Street". El uso de la solución propuesta por dheerosaur produce "321 A Broadway Street".
MoreScratch
También es agradable, deja intactos los acrónimos en el título. 'desarrollo de TIaSR innovador' se convierte en 'Desarrollo de TIaSR innovador'.
Matthias Arras
22

Existen estos métodos:

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

No hay opción de artículo en minúsculas. Tendría que codificarlo usted mismo, probablemente usando una lista de artículos que desea reducir.

nosklo
fuente
titlecase.py artículos en minúsculas.
TRS-80
14

Stuart Colville ha realizado una adaptación de Python de un script de Perl escrito por John Gruber para convertir cadenas en mayúsculas y minúsculas, pero evita usar mayúsculas en palabras pequeñas según las reglas del Manual de estilo del New York Times, además de atender varios casos especiales.

Parte de la inteligencia de estos guiones:

  • escriben con mayúscula palabras pequeñas como if, in, of, on , etc., pero las quitarán de mayúscula si se escriben con mayúscula errónea en la entrada.

  • los guiones asumen que las palabras con letras mayúsculas distintas del primer carácter ya están en mayúscula correctamente. Esto significa que dejarán una palabra como "iTunes" sola, en lugar de convertirla en "ITunes" o, peor aún, "Itunes".

  • omiten cualquier palabra con puntos de línea; “Example.com” y “del.icio.us” permanecerán en minúsculas.

  • tienen trucos codificados específicamente para tratar casos extraños, como "AT&T" y "Q&A", los cuales contienen palabras pequeñas (arroba y a) que normalmente deben estar en minúsculas.

  • La primera y la última palabra del título siempre se escriben con mayúscula, por lo que una entrada como "Nada que temer" se convertirá en "Nada que temer".

  • Una pequeña palabra después de dos puntos se escribirá en mayúscula.

Puedes descargarlo aquí .

BioGeek
fuente
4
capitalize (word)

Esto debería bastar. Lo entiendo de otra manera.

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

De acuerdo, como se dijo en la respuesta anterior, debe hacer una mayúscula personalizada:

mytext = u'yo soy un 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)   

Esto salidas

I am a Foobar Bazbar
pyfunc
fuente
Eso no es lo que quiero. Quiero obtener "Soy un Foobar Bazbar"
yassin
@Yassin Ezbakhe: Edité mi respuesta, esto debería funcionar para ti. La lista de artículos se puede extraer fácilmente de cualquier diccionario
pyfunc
2

El método de título de Python 2.7 tiene una falla.

value.title()

devolverá Carpenter ' S Assistant cuando el valor sea Carpenter 's Assistant

La mejor solución es probablemente la de @BioGeek usando titlecase de Stuart Colville. Cuál es la misma solución propuesta por @Etienne.

codificador de barco
fuente
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
"""

El título comienza con una palabra en mayúscula y no coincide con el artículo.

Tony Veijalainen
fuente
1

Una línea usando la comprensión de listas y el operador 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)

Descompostura:

for word in "Wow, a python one liner for titles".split(" ") Divide la cadena en una lista e inicia un ciclo for (en la comprensión de la lista)

word.title() if word not in "the a on in of an" else wordusa el método nativo title()para titular la cadena en mayúsculas y minúsculas si no es un artículo

" ".join une los elementos de la lista con un separador de (espacio)

usuario7297223
fuente
0

Un caso importante que no se está considerando son los acrónimos (la solución python-titlecase puede manejar acrónimos si los proporciona explícitamente como excepciones). En cambio, prefiero simplemente evitar la reducción de la carcasa. Con este enfoque, los acrónimos que ya están en mayúsculas permanecen en mayúsculas. El siguiente código es una modificación del originalmente proporcionado por 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))

Cuando se ejecuta, produce lo siguiente:

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.
Agosto Oeste
fuente