String in eine Liste

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Patejoker
User
Beiträge: 4
Registriert: Montag 24. April 2017, 09:57

Hallo erstmal.

Kurz zu meinem Problem

Ich würde gerne eine Usereingabe aufteilen.
Da die Usereingabe aber ein String zurück gibt ist das ganze nicht so einfach.

An sich soll der Benutzer folgenden eingeben: 1,2,3,4,(5,6,7(8,9,a,b),V)
zum Beispiel

Nun möchte ich diese eingabe ein wenig auf teilen und das ganze als ausgabe ausgeben.
Aber halt als

Hier sind ihre zahlen:
Hier ihre Tupple
Hier die Lsiten

Das ich alles ausgegeben bekomme sortiert als int, Strings und einzelnen Buchstaben habe ich schon hinbekommen.
Jedoch nicht das ich die Tupple und Listen als tupple und Listen zurück bekommen.

Hier mal mein Code um die Komplette eingabe aufzuteilen und als sortiertes einzelnes auszugeben.

Eventuell versteht ja jemand was ich möchte und kann mir helfen, kann es nicht wirklich beschreiben :(

Code: Alles auswählen

resultint=[]
resultstr=[]
resultword=[]

###Prüfen auf inhalt der Liste
def check(liste):
    # iteration durch die Liste und sortieren in passenden unterlisten
    for i in liste:
        try:
            i = int(i)
            resultint.append(i)
        except:
          #  if i in liste =="(" or i in liste =="[":
          #      continue
            if type(i) == list or type(i) == tuple:
                 check(i)
            elif type(i) == str and len(i)==1:
                resultstr.append(i)
            else:
                resultword.append(i)

def bubblesort(sorti):
    durchlaeufe = len(sorti)

    while durchlaeufe >= 1:

        for k in range(len(sorti) - 1):

            if sorti[k] > sorti[k+1]:

                sorti[k],sorti[k+1]=sorti[k+1],sorti[k]

        durchlaeufe = durchlaeufe - 1

    return sorti

while True:
    #1,2,3,(4,5,6),7,[Hallo,Danke,Bitte),a,b,c,d,g,e,(a,(b,[c],e),a),n
    eingabe= input("Bitte geben Sie das ihre Daten ein getrennt durch ein ,\nIhr Eingabe bitte:")
    eingabe = eingabe.replace("(","").replace(")", "").replace("[", "").replace("]","")
    liste = eingabe.split(',')
    print(type(eingabe))
    check(liste)
    bubblesort(resultint)
    bubblesort(resultstr)
    bubblesort(resultword)
    print("Es wurden folgende Zahlen eingegeben",resultint)
    print("Es wurden folgende Buchstaben eingegeben",resultstr)
    print("Es wurden folgende Worte eingegeben",resultword)
    break
Wie gesagt der Code gibt mir alles aufgeteilt aus.
Das sollte die neue Version nicht machen , sondern die touple als touple zurück geben
Zuletzt geändert von Anonymous am Montag 24. April 2017, 10:28, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Patejoker: wenn Du die Listen als Listen behalten willst, dann solltest Du nicht alle Klammern bei der Eingabe durch nichts ersetzen. Und die Prüfung, ob im Eintrag eine Klammer vorkommt (sollte i.startswith('(') heißen) muß nur das richtige (eine neue Liste erzeugen) machen. Die type-Prüfungen sind quatsch, da i immer nur ein String sein kann. Du weißt, dass es sort schon gibt? Schreibe Funktionen, die ihre Ergebnisse per return zurückgeben und benutze keine globalen Variablen.
Patejoker
User
Beiträge: 4
Registriert: Montag 24. April 2017, 09:57

Das es sort gibt weiss ich wohl, jedoch sollte ich die Bubblesort selber schreiben.

Der Code von mir war für die erste Übung wie ich bereits geschrieben hatte und in der war es die Aufgabe alles aufzuspliten und in die passenden Kategorien zu schieben halt ohne Klammern ;)

Die zweite Aufgabe ist nun das ausgeben einer neuen Liste in der die Tuple auch wieder Tuple sind und listen wieder listen
BlackJack

@Patejoker: Da brauchst Du einen richtigen Parser für, da laut Beispiel ja auch verschachtelte Tupel vorkommen können. Und mit Fehlern müsste der dann auch umgehen können, denn im Beispiel im Quelltext als Kommentar stimmt die Klammerung nicht.

Die `check()`-Funktion macht viel mehr als etwas zu prüfen. Was eine Funktion macht, sollte aus dem Namen ersichtlich sein. Zudem verändert sie globalen Zustand, womit es keine reine Funktion mehr ist. Alles was eine Funktion verwendet was keine Konstanten sind, sollte als Argument übergeben werden und Ergebnisse als Rückgabewerte an den Aufrufer zurückgegeben werden. Sonst erfüllen Funktionen nicht den Zweck in sich geschlossene, isolierte Teilaufgaben zu erfüllen, die man leicht nachvollziehen und testen kann.

Auf Modulebene sollte sowieso nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Dann kommt man auch gar nicht erst in die Versuchung in einer Funktion oder Methode irgendwelchen globalen Zustand benutzen oder gar verändern zu wollen. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

`i` als Laufvariable in einer Schleife sollte nur für ganze Zahlen verwendet werden. Alles andere ist sehr überraschend und verwirrend.

*Alle* Ausnahmen mit einem nackten ``except:`` zu behandeln ist fast immer falsch und kann die Fehlersuche enorm erschweren. Man sollte immer nur konkret die Ausnahmen behandeln die man auch erwartet, sonst werden auch alle unerwarteten so behandelt und man bekommt nicht mit was da genau passiert ist, sondern wundert sich am Ende nur über unerwartete/falsche Ergebnisse und muss dann erst einmal anfangen zu suchen.

Typprüfung mit ``type(obj) == some_type`` ist nicht gut. Dafür ist die `isinstance()`-Funktion gedacht. Die Prüfung macht auch erst Sinn wenn denn tatsächlich andere Datentypen ausser Zeichenketten hereinkommen können. *Dann* würde man aber auch erwarten das Zahlen schon als Zahlen vorliegen und nicht mehr geparst werden müssen.

Als Wort wird alles angesehen was nicht ganze Zahl, Tuple, Liste, oder Zeichenkette der Länge 1 ist. Also da wird kein Test gemacht ob es sich um eine Zeichenkette handelt. Das würde ich prüfen und einen ``else``-Zweig ans Ende packen der Alarm schlägt wenn die Funktion auf etwas trifft was nicht den Erwartungen entspricht.

`bubblesort()` kannst Du rauswerfen: Listen haben eine `sort()`-Methode.

Die ``while``-Schleife dort wäre übrigens eher eine ``for``-Schleife, beziehungsweise würde man die bei einer ernsthaften Implementierung eher durch ein Flag ersetzen das anzeigt ob es Vertauschungen gab. Denn die Länge der Eingabedaten ist in diesem Fall ja der „worst case“, in der Regel kann man früher abbrechen.

Die ``while``-Schleife auf Modulebene ist keine Schleife da der Schleifenkörper grundsätzlich genau *einmal* ausgeführt wird. Also weg damit.

Nach der Eingabe entfernst Du eckige und runde Klammern. Damit hat sich jegliche Möglichkeit erledigt Listen und Tupel zu erkennen.

Ich würde dann ungefähr bei so etwas landen (ungetestet):

Code: Alles auswählen

from __future__ import absolute_import, division, print_function


def partition(values):
    numbers = list()
    letters = list()
    words = list()

    def recurse(values):
        for value in values:
            try:
                numbers.append(int(value))
            except ValueError:
                if isinstance(value, (list, tuple)):
                    recurse(value)
                elif isinstance(value, str):
                    if len(value) == 1:
                        letters.append(value)
                    else:
                        words.append(value)
                else:
                    raise ValueError(
                        'unexpected value {0!r} of type {1}'.format(
                            value, type(value)
                        )
                    )

    recurse(values)
    return numbers, letters, words
 

def main():
    #1,2,3,(4,5,6),7,[Hallo,Danke,Bitte),a,b,c,d,g,e,(a,(b,[c],e),a),n
    eingabe = input(
        'Bitte geben Sie das ihre Daten ein getrennt durch ein ,\n'
        'Ihr Eingabe bitte:'
    )
    for charachter in '()[]':
        eingabe = eingabe.replace(charachter, '')
    liste = eingabe.split(',')
    results = partition(liste)
    for result in results:
        result.sort()
    numbers, letters, words = results
    print('Es wurden folgende Zahlen eingegeben', numbers)
    print('Es wurden folgende Buchstaben eingegeben', letters)
    print('Es wurden folgende Worte eingegeben', words)


if __name__ == '__main__':
    main()
Wie schon gesagt ist das Stichwort hier Parser. Als erstes stellt sich da die Frage ob Du am Eingabeformat etwas ändern kannst. Du sprichst von Listen und Tupeln als wenn es Python wäre, die Beispiel enthalten dann aber Buchstaben und Zeichenketten die nicht der Pythonsyntax entsprechen. Würden sie das tun, also Beispielsweise ``['Hallo','Welt']`` statt ``[Hallo,Welt]``, dann könnte man einfach `ast.literal_eval()` aus der Standardbibliothek verwenden um die Eingabe zu parsen.

Wenn man am Format der Eingabe nichts ändern kann könnte man sich selbst einen einfachen Parser schreiben, also beispielsweise mit dem `re`-Modul die Eingabe in Token zerlegen und dann einen „recursive descent“-Parser schreiben.

Oder, und das würde ich wohl machen, man nimmt eines der Python-Packages zum bauen von eigenen Parsern. Ich benutze da fast immer PyParsing, es gibt aber auch andere.
Patejoker
User
Beiträge: 4
Registriert: Montag 24. April 2017, 09:57

Erstmal danke für deine ausführliche Antwort:

Nunja es gab an sich folgenden Aussage:

Schreiben Sie ein Programm / Funktion / was auch immer um folgendes tun zu können:

Der User soll eine Eingabe getrennt von , durch führen.
Diese Eingabe soll zahlen, Buchstaben , tuple, listen und Wörter enthalten.
Nun Splitten Sie alles auf und sortieren es in Listen.

Diese Aufgabe hatte ich mit meinem nicht wirklich schönen aber funktionierendem Code gelöst.

Nun soll jedoch als Aufgabe zwei folgendens Passieren.

Die Usereingabe ist die gleiche, wieder mit komma getrennt.
Jedoch soll ich nun nicht alles auseinander ziehen und sortieren sondern tuple und listen sollen auch tuple und listen bleiben so das ich dann in der theorie die listen ansprechen kann und z.B. sagen kann index[2]von tuple liste1.

Ich hoffe das es nun verständlicher ist.


ALS HINWEISS .

DAS ALLES SOLLTE ICH HALT OHNE VORGEFERTIGTE FUNKTION WIE SORT MACHEN !
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Patejoker: die Aufgabenstellung ist, glaube ich, den meisten hier schon klar. Und dass Dein Code noch nicht so schön ist, wie der von BlackJack ist auch nicht weiter schlimm. Du solltest aber schon von Anfang an lernen, dass z.B. globale Variablen in einem ordentlichen Programm nichts verloren haben. Und wenn Du keine vorgefertigten Funktionen benutzen darfst, wie sieht das dann mit replace, append, print usw. aus?

Um die erweiterte Aufgabe zu lösen, brauchst Du einen Parser, der am einfachsten rekursiv arbeitet. Erster Schritt wäre, die Eingabe in Token aufzuspalten, also Zahl, Wort, Komma, Klammer auf/zu, usw. Erst wenn das erledigt ist, macht es Sinn, sich über das Zusammenbauen von rekursiven Listen gedanken zu machen.
Patejoker
User
Beiträge: 4
Registriert: Montag 24. April 2017, 09:57

Naja ich weiß auch nicht so genau was ich darf und was nicht , replace war auf alle Fälle erlaubt :roll:

Aber alles weitere ist so ne sache für sich.
Ich hatte als ansatzt bereits gedacht das ich folgenden machen.

Ich nehme den String (die Usereingabe) und gehe diesen durch.
Dann erzeuge ich mir ein counter der bei einer ( +1 rechnet und bei einer )-1 so hätte ich dann den Abschnitt einen tuples welches ich dann (auf welche art auch immer , das weiß ich noch nicht genau) wieder in eine Liste Tuple speicher.

In der Hoffnung das diese Liste dann nicht als String behandelt wird.

Mit den Zahlen und den Buchstaben würde ich einfach wie gehabt verfahren, prüfen und in die Liste schreiben
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Patejoker: beim Programmieren ist es immer hilfreich, ein komplexes Problem in einfachere Teilprobleme aufzuspalten. Und das erste Teilproblem ist es, die Eingabe in eine Liste von Token (Zahl, Klammer, etc.) aufzuspalten. Fang am besten damit an.
Antworten