Fehler bei Substrings

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
DrChAoS
User
Beiträge: 14
Registriert: Montag 10. März 2008, 16:29

Guten Abend,
Da bin ich wieder :lol:. Ich bin gerade dabei einen kleinen Interpreter für eine selbst ausgedachte Sprache in Python zu schreiben. Aber bei der Stringverarbeitung gibt es einen Fehler. Hier erstmal der Code:

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf-8 -*-

import sys

i=0
x=[0]*30000
lines=[0]*60000

dat = open(sys.argv[1],"r")

line = dat.readline()
k=0
while line != "":
    if line[:1] != "#":
        lines[k] = line
        k+=1
    line = dat.readline()
dat.close()

while 1:
    tmp_line = lines[i]
    if tmp_line[:1] == ".":
        out=""
        tok = tmp_line[1:].split(",")
        for t in tok:
            if t[:1]=="\"" and t[::-1][:1]=="\"" :
                out+=t[1:-1]
            elif t[:1]=="x":
                out+=str(x[int(t[1:])])
            else:
                print "Error in Line \n%s"%(tmp_line)
                exit()
 
    i+=1
Wenn in der Übergebenen Datei (./script.py test.txt) test.txt Das hier steht:

Code: Alles auswählen

#start
."Hallo",x3
#ende
Bekomme ich diesen Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "asms.py", line 33, in <module>
    if tmp_line[:1] == ".":
TypeError: 'int' object is unsubscriptable
Normalerweise sollte der Interpreter folgende Rückgabe machen:

Code: Alles auswählen

Hallo0
Ich sitze jetzt schon den ganzen Mittag an diesem (vermutlich) total simplen Fehler.
Vielen Dank schonmal im Vorraus.
MfG
Dr.ChAoS
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

Naja, schau doch mal auf den Error. int object ist unsubscriptable.
Das heißt tmp_line wird anscheinend zu einem int-Objekt.
Klar, wenn du lines mit 60.000 * [0] initialisierst.
Nach einem durchlauf, wenn i = 1 ist, kommts zu lines[1] -> 0 -> int -> Error
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Was mir spontan auffällt, dass einige Dinge völlig "unpythonisch" und in diesem Falle dadurch sehr ungeschickt gelöst sind.

Es dürfte nicht schaden, wenn du mal das offizielle Tutorial (so weit du es brauchst) durcharbeitest - das wird dir einige Aha-Erlebnisse bescheren und deinen Code auf geschätzte 25% des jetzigen Codes (bei gleicher Funktionalität) zusammenschmelzen.

2 Beispiele:
a) Sieh dir mal die readlines()-Methode von Dateiobjekten an!
b) Die while-Schleife mit Zähler ist hier die ganz falsche Lösung. Du kannst direkt über alle Elemente der Liste (also in deinem Falle alle Zeilen) iterieren.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Versuch das Slicing mal zu vermeiden. Ich sehe jetzt Spontan keine Stelle an der das notwendig ist.

Wie auch immer mich würde mal die Syntax interessieren. Das x3 was soll das bewirken und worauf soll die Bedingung in Zeile 27 zutreffen? Ich hab den Code mal neugeschrieben aber dass ist die einzige Zeile deren Sinn ich auch nach einigen Experimenten nich wirklich verstanden habe.

btw. Der Interpreter wird übrigens gar keine Ausgabe machen da nirgendswo ein print vorkommt.

EDIT: Zeile 27 soll den String finden oder? Wirklich unglaublich kompliziert gelöst. Ich glaub da ist doch noch ein Tipp nötig:
Es gibt 'string'.startswith('s') und 'string.endswith('g') ;)
DrChAoS
User
Beiträge: 14
Registriert: Montag 10. März 2008, 16:29

Karl hat geschrieben:Das heißt tmp_line wird anscheinend zu einem int-Objekt.
Klar, wenn du lines mit 60.000 * [0] initialisierst.
Vielen Dank, das war im Grunde mein größter Denkfehler.
numerix hat geschrieben:a) Sieh dir mal die readlines()-Methode von Dateiobjekten an!
Danke, damit wurde der Code wirklich kürzer und einfacher.
b) Die while-Schleife mit Zähler ist hier die ganz falsche Lösung. Du kannst direkt über alle Elemente der Liste (also in deinem Falle alle Zeilen) iterieren.
Nein, das kann ich nicht machen, denn ich muss den Zähler im späteren Verlaufs des Programms ändern können und das ist so nicht möglich.

@DasIch
Meine "Sprache" basiert ein kleines bisschen auf Brainfuck. x3 heißt dass ich auf das dritte Feld des Arrays x zugreife und den Wert ausgebe.
Hier noch ne kurze Erklärung der Syntax:
Variablen können nur Integer Werte enthalten.
. gibt etwas aus. Strings und Variablen werden durch ein Komma getrennt. Bsp:
# leitet einen Kommentar ein, der übrigens nicht hinter eine Zeile stehen kann^^.
, (Noch nicht implementiert) ließt einen Integer Wert ein.
dann kommen noch weitere dinge wie + - * / etc.. und auch eine If Abfrage. außerdem soll man zwischen den Zeilen springen können (Deswegen die while Schleife mit der Laufvariable)

EDIT: Jetzt hätte ich fast den Aktuellen Source vergessen: (Für diejenigen die es interessiert)

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf-8 -*-

import sys

x={}
for t in range(30000):
	x[t]=0
lines={}

dat = open(sys.argv[1],"r")
tmp_lines = dat.readlines()
dat.close()
l=0
for k in tmp_lines:
	lines[l]=k[:-1]
	l+=1
i=0
while i<len(lines):
    if lines[i][:1] == "#":
        pass
    elif lines[i][:1] == ".":
        out=""
        tok = lines[i][1:].split(",")
        for t in tok:
            if t[:1]==""" and t[::-1][:1]==""" :
                out+=t[1:-1]
            elif t[:1]=="x":
                out+=str(x[int(t[1:])])
            else:
                print "Error on Line %i \n%s"%(i+1,lines[i])
                exit()
        print out
 
    i+=1
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Sprache ist interessant.

Zum Code: Was soll Zeile 21? Benutze einfach pass dann ist klar dass nichts mehr passieren soll und man hat nicht noch ein Objekt rumliegen. Benutze besser Leerzeichen vor und nach Operatoren, das macht den Code besser lesbar und sieht auch besser aus.
Statt einen String umzudrehen kannst du gleich auf das letzte Zeichen mit [:-i] zugreifen.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

Ich hab ja auch letztens einen Brainfuckinterpreter im Showcase gepostet, der aber anscheinend irgendeinen Bug hat.
Ich erinner mich noch gut daran, wie ich aus Gewohnheit eine for-Schleife benutzt habe und dann mit dem Iterator bei einer Schleife zurückspringen wollte :roll: Mit while hat's dann natürlich geklappt :)
Du hast aber bis jetzt nur die unwichtigen Details deiner kleinen an Brainfuck angelehnten Sprache verraten.
Das wichtigste ist doch, wie du die Schleife realisieren willst.
Dass du auch vorhast, Zellen wie in Brainfuck zu benutzen, schließe ich aus x=[0]*30000, auch wenn ich mir dein "gewurstel" da unten noch nicht angeschaut hab. Du könntest ja wenigstens ein wenig öfter die Space-Taste benutzen :)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

DrChAoS hat geschrieben:
numerix hat geschrieben:b) Die while-Schleife mit Zähler ist hier die ganz falsche Lösung. Du kannst direkt über alle Elemente der Liste (also in deinem Falle alle Zeilen) iterieren.
Nein, das kann ich nicht machen, denn ich muss den Zähler im späteren Verlaufs des Programms ändern können und das ist so nicht möglich.
In welchem "späteren Verlauf"?
Innerhalb der Schleife jedenfalls nicht. Wenn du direkt über die Elemente der Liste (also über die Zeilen des "Quelltextes") iterierst, brauchst du keine Zählvariable. Die einzige Stelle, wo du die Zeilennummer verwendest, ist die Ausgabe der Zeilennummer bei einer Fehlermeldung.

Kennst du so etwas:

Code: Alles auswählen

datei = open(sys.argv[1],"r")
zeilen = datei.readlines()
datei.close()

for zeile in zeilen:
    if not zeile.startswith("#"):
        print "Interpretiere %s" %zeile
Und falls du die Zeilennummer für die Fehlermeldung brauchst:

Code: Alles auswählen

for nr,zeile in enumerate(zeilen):
    if not zeile.startswith("#"):
        print "[%i] Interpretiere %s" %(nr,zeile)
Sowas findet man im Tutorial ... :wink:
DrChAoS
User
Beiträge: 14
Registriert: Montag 10. März 2008, 16:29

Ich werde das so machen wie man es früher in C gemacht hat. Und zwar mit einer Art GOTO. Dazu Werde ich am Anfang die Zeilennummern aller Sprungstellen in ein dict schreiben um später Mit der Laufvariable einfach an die entsprechende Stelle Springen kann.
Und das in Kombination mit einer if Anweisung die im Falle von false die nächste Zeile überspringt macht es möglich Kopfgesteuerte und Fußgesteuerte Schleifen zu programmieren.
Hier ein kleines Beispiel:

Code: Alles auswählen

<x3,x2
j:sprung
."false"

:sprung
Wenn x3 kleiner x2 ist, wird nach :sprung gesprungen. Andernfalls wird der Text "false"
ausgegeben.

Zusätzlich zu ">" will ich noch "<" einbauen. Denn mit diesen zwei Operatoren kann man alles überprüfen.

So ich hoffe dass das so verständlich war :)
MfG
Dr.ChAoS

//EDIT:
@numerix: Aber Wie will ich dann Schleifen realisieren? Ich springe ja durch das Programm in dem ich die Laufvariable i verändere.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

DrChAoS hat geschrieben:@numerix: Aber Wie will ich dann Schleifen realisieren? Ich springe ja durch das Programm in dem ich die Laufvariable i verändere.
Alles klar; diesen kurzen Hinweis weiter oben hatte ich überlesen.
Ich war davon ausgegangen, dass es ein lineares Programm ist und mich nur auf das bezogen, was der Code bisher macht.

Für Sprünge brauchst du natürlich einen Index.
Antworten