3 Stimmen

Probleme bei der Groß-/Kleinschreibung einer Zeichenkette in Python

Ich habe einen Namen als String, in diesem Beispiel "markus johansson".

Ich versuche, ein Programm zu programmieren, das 'm' und 'j' in Großbuchstaben schreibt:

name = "markus johansson"

for i in range(1, len(name)):
    if name[0] == 'm':
        name[0] = "M"
    if name[i] == " ":
        count = name[i] + 1
    if count == 'j':    
            name[count] = 'J'  

Ich bin mir ziemlich sicher, dass dies funktionieren sollte, aber ich erhalte diese Fehlermeldung:

File "main.py", line 5 in <module> 
   name[0] = "M" 
TypeError: 'str' object does support item assignment 

Ich weiß, dass es eine Bibliotheksfunktion namens .title() gibt, aber ich möchte "richtig programmieren".

Wie kann ich das beheben?

0 Stimmen

Ich schlage vor, dass Sie den Titel verbessern

0 Stimmen

Echte Programmierer verwenden die ihnen zur Verfügung stehenden Werkzeuge, insbesondere Bibliotheken.

0 Stimmen

Wer will schon ein richtiger Programmierer sein?

1voto

Tyson Punkte 6154

Wenn ich Ihren ursprünglichen Algorithmus richtig verstehe, ist es das, was Sie tun wollen:

namn = list("markus johansson")

if namn[0] == 'm':
    namn[0] = "M"

count = 0

for i in range(1, len(namn)):
    if namn[i] == " ":
        count = i + 1
    if count and namn[count] == 'j':    
        namn[count] = 'J'

print ''.join(namn)

Natürlich gibt es eine Million besserer Wege ("Möchtegern"-Wege), um das zu tun, was du versuchst zu tun, wie in der Antwort von vartec gezeigt :)

So wie es aussieht, funktioniert Ihr Code nur für Namen, die mit einem J und einem M für den Vornamen bzw. Nachnamen beginnen.

1voto

Jarret Hardie Punkte 89900

Viele gute Vorschläge, also bin ich in guter Gesellschaft, wenn ich meine eigenen 2 Cents hinzufüge :-)

Ich gehe davon aus, dass Sie etwas Allgemeineres wollen, das mehr als nur mit Namen umgehen kann, die mit "m" und "j" beginnen. Sie werden wahrscheinlich auch Namen mit Bindestrich in Betracht ziehen wollen (wie Markus Johnson-Smith), die ebenfalls Großbuchstaben nach dem Bindestrich haben.

from string import lowercase, uppercase
name = 'markus johnson-smith'

state = 0
title_name = []

for c in name:
    if c in lowercase and not state:
        c = uppercase[lowercase.index(c)]
        state = 1
    elif c in [' ', '-']:
        state = 0
    else:
        state = 1 # might already be uppercase

    title_name.append(c)

print ''.join(title_name)

Der letzte Vorbehalt ist das Potenzial für Nicht-Ascii-Zeichen. Die Verwendung des uppercase et lowercase Eigenschaften der string Modul ist in diesem Fall gut, da sich ihr Inhalt je nach dem Gebietsschema des Benutzers ändert (d.h. systemabhängig oder wenn locale.setlocale() aufgerufen wird). Ich weiß, Sie wollen die Verwendung von upper() für diese Übung, und das ist ganz nett... zu Ihrer Information, upper() verwendet die locale kontrolliert von setlocale() auch, so dass die Praxis der Nutzung uppercase et lowercase ist eine gute Verwendung der API, ohne zu hoch zu werden. Das heißt, wenn Sie z.B. französische Namen auf einem System mit englischem Gebietsschema behandeln müssen, brauchen Sie eine robustere Implementierung.

0 Stimmen

uppercase[lowercase.index(c)] macht es O(N**2). Verwenden Sie c.islower() , c.lower() , usw.

0 Stimmen

Völlig einverstanden ... nur versuchen, ihm zu helfen, die Verwendung von Bibliotheksfunktionen gemäß seiner Frage zu vermeiden.

0voto

Andrew Dalke Punkte 14207

"echte Programmierung"?

Ich würde .title() verwenden, und ich bin ein echter Programmierer.

Oder ich würde reguläre Ausdrücke verwenden

re.sub(r"(^|\s)[a-z]", lambda m: m.group(0).upper(), "this   is a set of  words")

Hier heißt es: "Wenn auf den Textanfang oder ein Leerzeichen ein Kleinbuchstabe folgt" (auf Englisch - andere Sprachen werden wahrscheinlich nicht unterstützt), dann wird bei jeder Übereinstimmung der übereinstimmende Text in Großbuchstaben umgewandelt. Da es sich bei dem übereinstimmenden Text um das Leerzeichen und den Kleinbuchstaben handelt, funktioniert dies einwandfrei.

Wenn Sie es als Low-Level-Code haben wollen, funktioniert das Folgende. Hier lasse ich nur Leerzeichen als Trennzeichen zu (aber vielleicht möchten Sie auch Zeilenumbrüche und andere Zeichen unterstützen). Andererseits ist "string.lowercase" internationalisiert, d.h. wenn Sie sich in einem anderen Gebietsschema befinden, wird es größtenteils trotzdem funktionieren. Wenn Sie das nicht wollen, dann verwenden Sie string.ascii_lowercase.

import string

def title(s):
    # Capitalize the first character
    if s[:1] in string.lowercase:
        s = s[0].upper() + s[1:]

    # Find spaces
    offset = 0
    while 1:
        offset = s.find(" ", offset)
        # Reached the end of the string or the
        # last character is a space
        if offset == -1 or offset == len(s)-1:
            break

        if s[offset+1:offset+2] in string.lowercase:
            # Is it followed by a lower-case letter?
            s = s[:offset+1] + s[offset+1].upper() + s[offset+2:]
            # Skip the space and the letter
            offset += 2
        else:
            # Nope, so start searching for the next space
            offset += 1

    return s

Um auf meinen Kommentar zu dieser Antwort einzugehen: Diese Frage kann nur eine Übung aus Neugier sein. Echte Namen haben besondere Regeln für die Großschreibung: Das "van der" in "Johannes Diderik van der Waals" wird nie großgeschrieben, "Farrah Fawcett-Majors" hat ein "M", und "Cathal Ó hEochaidh" verwendet das nicht-ASCII-konforme "Ó" und "h", die "Eochaidh" zu "Enkel von Eochaidh" modifizieren.

0 Stimmen

Bei langen Eingaben, z. B. 50.000 Wörtern oder mehr, ist die Leistung schlecht. Das liegt daran, dass Sie die Zeichenkette für jedes Wort neu erstellen müssen. Die Big-O-Komplexität ist wahrscheinlich schlechter als linear. Es wäre wahrscheinlich effizienter, die Zeichenfolge in einem StringIO-Objekt zu erstellen.

0 Stimmen

Übrigens, eine einfache Möglichkeit, eine lange Eingabe für Tests zu erzeugen: s = 'test ' * 50000

0 Stimmen

Ja, quadratisch mit der Anzahl der Substitutionen. Aber 1) dies ist nicht als allgemeiner Code gedacht 2) der OP wollte einen Code auf Zeichenebene 3) 1000 Ersetzungen sind immer noch < 1ms 4) wer benutzt Titel wirklich? besonders da i18n, "Anführungszeichen", etc. die Dinge durcheinander bringen, 5) Titel auf Namen wie "van der Waal" ist falsch.

0voto

string = 'markus johansson'

string = ' '.join(substring[0].upper() + substring[1:] for substring in string.split(' '))

# string == 'Markus Johansson'

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X