Variablen aus einer txt datei

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
Morila
User
Beiträge: 8
Registriert: Freitag 4. März 2016, 11:30

Hey Leute. Ich versuche schon seit geraumer zeit aus einer g-code-txt Datei zeile für Zeile die variablen zu entnehmen.

Mein Code sieht so aus

Code: Alles auswählen

Lines[]
Text = open("pfad/Datei", "r")
For Line in text.readlines():
    lines.append(line)
Text.Close

I=0

While (1==1):
   Print (Lines[i])
   i= (i+1)

Print ("ende")
Das ergebnis ist, dass ich mit print(lines) und i als zeilenangabe den Inhalt der Zeile auslesen kann.

Die txt Datei lautet:

( This file created by CNC_profile.rb )
( Cutter Diameter: 0.11811023622047245 )
( Stock Size: 4.0551181102362195 x 4.055118110236214 x 0.3937007874015748 )
G21 ( Unit of measure: millimeter )
G90 ( Absolute programming )
M03 ( Spindle on [clockwise] )

G00 Z13,000 F30 (Move safety height)
G00 X0.00 Y.00 F100 ( Move to origin )
G00 X-1,500 Y-1,500 F100
G01 Z0.0 F15
G01 X-1,500 Y-1,500 Z0,000 F50
G01 X-1,500 Y101,500 Z0,000 F50
G01 X101,500 Y101,500 Z0,000 F50
G01 X101,500 Y-1,500 Z0,000 F50
G01 X-1,500 Y-1,500 Z0,000 F50
G00 Z13,000 F30

G00 X0.00 Y.00 F100( Move to origin )
M05 ( Spindle stop )
M02 ( End of program )

end

Im grunde währe ein Befehl perfeckt der folgendes tuht:

Wenn zeile(A) nicht leer ist,Lies Zeile(A)
Gib variablen aus zeile(A)aus.
G=
X=
Y=
Z=
A=A+1
Tuhe etwas mit den variablen


Das Programm sollte in einer while schleife Zeile für Zeile die x,y und z werte als variablen behandeln können. Ich habe ein der. Teilprugram, das : punkt_anfahren(x,y,z) Heißt.
Ich mochte dass er aus der txt Datei zuerst den punkt in zeile1 anführt, dann in zeile 2 usw.
Bitte helft mir. Ich bin ratlos.

Euer Morila
Zuletzt geändert von Anonymous am Sonntag 6. März 2016, 14:11, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
BlackJack

@Morila: So sieht Dein Code bestimmt nicht aus, beziehungsweise würde der so nicht laufen, denn er ist voller Syntaxfehler.

Ich glaube Klammern um Bedingungen un den Unsinn von ``1 == 1`` hatten wir schon mal. Eine ``while``-Schleife ist hier auch fehl am Platz. Und selbst eine ``for``-Schleife über Indexwerte ist kein Python, denn in Python kann man über die Elemente eine Liste auch direkt iterieren, ohne den Umweg über einen Index. Auch über die Zeilen einer Textdatei kann man direkt über das Dateiobjekt iterieren ohne die mit einer Methode vorher komplett in den Speicher laden zu müssen. Gross- und Kleinschreibung von Namen wird unterschieden und wenn man Methoden aufrufen will, dann muss man die auch tatsächlich *aufrufen* und nicht einfach nur derefenzieren. ``text.Close`` ist was anderes als ``text.close`` und das wiederum ist etwas anderes als ``text.close()``. Wobei man hier eher mit der ``with``-Anweisung dafür sorgen würde das die Datei unter allen Umständen geschlossen wird.

Ich denke Du müsstest mal ein Python-Grundlagentutorial wirklich durcharbeiten, statt versuchen von einer anderen Programmiersprache kommend (BASIC?) zu raten wie das wohl in Python aussieht.

Befehle gibt's in Python nur sehr wenige. Einen magischen Befehl der das machst was Du willst ganz bestimmt nicht. Das wirst Du Dir aus den wenigen Befehlen, den Operatoren, und den vielen, vielen Funktionen und Datentypen aus der Standardbibliothek (und je nach Problem auch Module/Packages ausserhalb der Standardbibliothek) selber als Funktion(en) und/oder eigenen Datentypen schreiben müssen.

Da gilt grundsätzlich die übliche Vorgehensweise: Probleme in kleinere Teilprobleme zerlegen und die wieder zerlegen solange bis man an einem Punkt angelangt ist, an dem man das jeweilige Problem mit einer Funktion mit ein paar Zeilen Code lösen kann. Dann die Teillösung testen, zur nächsten Teillösung weitergehen, die Teillösungen zu grösseren (Teil)Lösungen zusammensetzen, immer schön testen, und am Ende hat man dann eine Gesamtlösung.

Ich hatte es in einem anderen Thema ja schon geschrieben: Du willst nicht das da wirklich Python-Variablen gesetzt werden. Du hast keine Kontrolle darüber was in der Textdatei steht, da könnten dann also auch Namen definiert und beim verarbeiten dann überschrieben werden, die in Deinem Programm eine Bedeutung haben. Im besten Fall fällt Dein Programm dann einfach nur auf die Nase, im schlechtesten Fall nutzt das jemand um eine Eingabedatei zu konstruieren die in Dein Programm eingreift und versucht beliebigen Code einzuschleusen und auszuführen.

Diese Dateien scheinen zeilenweise aufgebaut zu sein. Du müsstest also entscheiden ob Dich eine Zeile interessiert oder nicht. Und falls Dich eine Zeile interessiert musst Du sie in eine Datenstruktur überführen mit der Du weiterarbeiten kannst. Beispielweise ein Wörterbuch (`dict`) das die ”Variablen” auf die Werte abbildet. Dazu brauchst Du Python-Grundlagenwissen. Die grundlegenden Datenstrukturen, Zeichenkettenoperationen, und eventuell das `re`-Modul.
Benutzeravatar
pixewakb
User
Beiträge: 1409
Registriert: Sonntag 24. April 2011, 19:43

Möglicherweise lohnt ein Blick auf dieses Modul:

https://docs.python.org/3.5/library/configparser.html

Ich merke an, dass der Name sich zu Version 2.x geändert hat, d. h. falls Du Python 2.7 nutzt, schau noch mal genau in die Hilfe. Eine Bekannte nutzt das Modul m. E. sehr massiv, jedenfalls erinnere ich mich an Codebeispiele. Ich selbst habe damit keine Erfahrung.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Hallo Morila
Ich glaube bei dieser Syntax kommst du beim Parsen mit der Funktion split und den slice-Operationen aus (Python Tutorial):

Code: Alles auswählen

>>> 'G21 ( Unit of measure: millimeter )'.split('(')
['G21 ', ' Unit of measure: millimeter )']
>>> 'G01 X-1,500 Y-1,500 Z0,000 F50'.split()
['G01', 'X-1,500', 'Y-1,500', 'Z0,000', 'F50']
>>> 'X-1,500'[:1]
'X'
>>> 'X-1,500'[1:]
'-1,500'
>>> '-1,500'.split(',')
['-1', '500']
>>> '1.0'.split(',')
['1.0']
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Hier ein Beispiel, das dir verschiedene Konstrukte zeigt, die du bei deinem Programm benötigen könntest.

Code: Alles auswählen

import re

inputfile='./gcode.txt'

gint=re.compile('^[+-]?[0-9]+$')
gfloat=re.compile('^[+-]?(([0-9]+\.)|([0-9]*\.[0-9]+))$')

def do_G00(var_list):
    print('function G00',var_list)

def do_G01(var_list):
    print('function G01',var_list)

def do_G21(var_list):
    print('function G21',var_list)

def do_G90(var_list):
    print('function G90',var_list)
    
def do_M02(var_list):
    print('function M02',var_list)
    
def do_M03(var_list):
    print('function M03',var_list)
    
def do_M05(var_list):
    print('function M05',var_list)
    
with open(inputfile, 'r') as f:
    for line in f.readlines():
        line=line.rstrip()
        parts=line.split('(')
        if parts:
            code=parts[0]
            parts=code.split()
            if parts:
                cmd=parts[0]

                # parse arguments:
                var_dict={}
                arglist=parts[1:]
                for arg in arglist:
                    var=arg[:1]
                    vals=arg[1:].split(',')
                    value_list=[]
                    for val in vals:
                        if gint.match(val):
                            value_list.append(int(val))
                        elif gfloat.match(val):
                            value_list.append(float(val))
                        elif val=='':
                            pass
                        else:
                            raise Exception('value error',val,line)
                    if not value_list:
                        var_dict[var]=None
                    elif len(value_list)==1:
                        var_dict[var]=value_list[0]
                    else:
                        var_dict[var]=value_list
                        
                print('line:',line)
                if cmd=='G00':
                    do_G00(var_dict)
                elif cmd=='G01':
                    do_G01(var_dict)
                elif cmd=='G21':
                    do_G21(var_dict)
                elif cmd=='G90':
                    do_G90(var_dict)
                elif cmd=='M02':
                    do_M02(var_dict)
                elif cmd=='M03':
                    do_M03(var_dict)
                elif cmd=='M05':
                    do_M05(var_dict)
                else:
                    raise Exception('invalid command',cmd,line)
                
Im Abschnitt '#parse arguments' dient vor allem dazu zu zeigen, wie mit Hilfe von regulären Ausdrücke Zahlenformate überprüft werden können. und dann in die entsprechenden Datentypen konvertiert werden können. Die Variablen werden in einem Dictionary hinterlegt. Da aber die möglichen Variablennamen vermutlich fest vorgegeben sind, kann man das auch ohne Dictionary lösen, z.B. indem man den Variablen varX, varY, varZ, varF die Werte der gcode-Variablen X,Y,Z und F zuweist.
Die Fehlerbehebung und die Überprüfung der Eingabe ist auch sehr enfach implementiert und sollte ausgebaut werden.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@miracle173: wenn man 9 Einrückebenen hat, dann ist das ein deutliches Zeichen dafür, dass man eigentlich mehr Funktionen benötigt.
readlines ist überflüssig, da direkt über ein Fileobjekt iteriert werden kann. Ein String der mit split in eine Liste konvertiert wird, besteht immer aus mindestens einem Element, so dass die if-Abfrage danach immer True ergibt. Bei der Konstruktion mit der Value-Liste machst Du Dir Dein Leben unnötig schwer. Entweder gibt es eine Regel, dass bestimmte Argumente nur eine Zahl als Parameter haben, dann sollte diese Bedingung gleich geprüft werden, oder man definiert die Parameter aller Argumente als Liste, weil man später ja sonst prüfen müßte, ob das entsprechende Argument eine Liste ist, also nochmal eine Fallunterscheidung machen, um die erste wieder rückgängig zu machen. Statt der langen if-elif-Kette für die einzelnen Funktionen böte sich ein Wörterbuch an. Den Typ einer Variable sollte man nicht in den Namen schreiben, der kann sich nämlich mit der Entwicklung ändern und dann müßte man an allen Stellen die Variable umbenennen.

Code: Alles auswählen

from contextlib import contextmanager

INPUTFILE = './gcode.txt'

@contextmanager
def read_commands(filename):
    with open(filename) as lines:
        for line in lines:
            # strip away comment
            line = line.split('(', 1)[0].strip()
            if line:
                parts = line.split()
                yield parts[0], parts[1:]

def parse_arguments(arguments):
    result = {}
    for arg in arguments:
        values = arg[1:].split(',')
        result[arg[0]] = [float(v) if v else None for v in values]
    return result


def do_G00(var_list):
    print('function G00',var_list)

def do_G01(var_list):
    print('function G01',var_list)

def do_G21(var_list):
    print('function G21',var_list)

def do_G90(var_list):
    print('function G90',var_list)
    
def do_M02(var_list):
    print('function M02',var_list)
    
def do_M03(var_list):
    print('function M03',var_list)
    
def do_M05(var_list):
    print('function M05',var_list)

CMD2FUNC = {
    'G00': do_G00,
    'G01': do_G01,
    'G21': do_G21,
    'G90': do_G90,
    'M02': do_M02,
    'M03': do_M03,
    'M05': do_M05,
}

with read_commands(INPUTFILE) as commands:
    for cmd, arguments in commands:
        variables = parse_arguments(arguments)
        print('line:', cmd, variables)
        try:
            func = CMD2FUNC[cmd]
        except KeyError:
            raise RuntimeError("Unknown command %s" % cmd)
        else:
            func(variables)
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Sirius3 hat geschrieben:@miracle173: wenn man 9 Einrückebenen hat, dann ist das ein deutliches Zeichen dafür, dass man eigentlich mehr Funktionen benötigt.
Wobei natürlich sich hier die Frage auftut wieviele Ebenen nun zuviel sind. Der Linux Kernel zieht die Grenze bei 3. Dementsprechend würde ich auf Python übertragen würde die Grenze bei 1, 4 und 5 ziehen, abhängig davon ob man sich im Modul, einer Funktion oder einer Methode befindet.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

im nc programmsatz wird doch immer durch leerzeichen getrennt.
einfach splitten, dann immer den ersten(0) eintrag parsen und entsprechend abarbeiten.
ggf. wenn du Satznummer N... vorn hast, eben erst den zweiten(1).

hier wäre interessant was du mit den variablen machen willst.

btw. M30 Programmende fehlt.
empty Sig
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Sirius3 hat geschrieben:@miracle173: wenn ...
@Sirius
Danke für die konstruktive Kritik. Allerdings bin ich nicht mit allem einverstanden, darum möchte ich auf deine Kritikpunkte im Einzelnen eingehen.

+wenn man 9 Einrückebenen hat, dann ist das ein deutliches Zeichen dafür, dass man eigentlich mehr Funktionen benötigt.
Da hast du recht. Ich habe keine verwendet, da sich nichts an Code wiederholt. Man kann zwar zwei Einzüge vermeiden, indem man statt if ein if/break verwendet, aber das will ich eigentlich nicht. Durch Verwendung von aussagekräftigen Funktionen erhöht sich ja auch wesentlich die Lesbarkeit des Codes und macht den Kommentar dann völlig überflüssig. Ich war da aber zu bequem.
Allerdings ist die Implementation mit Hilfe der contextmanager-Annotation und des yield Befehls jenseits meiner derzeitigen Sprachkenntnisse, und vermutlich auch der des OP, darum werde ich das vorläufig nicht verwenden. Ich werde mich damit, sobald es mir möglich ist, auseinander setzen.

+readlines ist überflüssig, da direkt über ein Fileobjekt iteriert werden kann.
Der Grund warum ich diese Programm geschrieben habe, war der folgende Satz in einem anderen Post
BlackJack hat geschrieben:...
Auch über die Zeilen einer Textdatei kann man direkt über das Dateiobjekt iterieren ohne die mit einer Methode vorher komplett in den Speicher laden zu müssen...
Ich wollte untersuchen, wie man in Python das implementiert. Ich habe da offenbar nicht ausreichend recherchiert.
readline soll natürlich entfallen.

+Ein String der mit split in eine Liste konvertiert wird, besteht immer aus mindestens einem Element, so dass die if-Abfrage danach immer True ergibt.
Das habe ich übersehen. Eigentlich will ich überprüfen, ob line bzw code leer ist. Das sollte ich auch tun, und nicht die Ergebnisliste der Splitoperation, die auch beim Split eines Leerstrings ein Element, nämlich einen Leerstring, enthält.

-Bei der Konstruktion mit der Value-Liste machst Du Dir Dein Leben unnötig schwer. Entweder gibt es eine Regel, dass bestimmte Argumente nur eine Zahl als Parameter haben, dann sollte diese Bedingung gleich geprüft werden, oder man definiert die Parameter aller Argumente als Liste, weil man später ja sonst prüfen müßte, ob das entsprechende Argument eine Liste ist, also nochmal eine Fallunterscheidung machen, um die erste wieder rückgängig zu machen.
Nein, das stimmt nicht. Ich mache mir nicht das Leben schwer, das ist einfach notwendig. Wenn du dir diese Zeilen aus der Beispieldatei anschaust

Code: Alles auswählen

G00 X0.00 Y.00 F100 ( Move to origin )
G00 X-1,500 Y-1,500 F100
siehst du, dass es keine Regel gibt und dass beim gleichen Kommando Parameter sowohl zweidimensionale Vektoren als auch Skalare sein können. Warum auch nicht? Warum soll man später keine Fallunterscheidung machen? Das ist nichts schlechtes. Ziel des Parsers ist es, die Syntax in Python-geeignete Strukturen zu transformieren, ohne all zu viel Wissen über die gcode-Syntax zu wissen. Dieses Wissen kann dann in den einzelnen Funktionen verwendet werden, um die Strukturen noch einmal zu überprüfen.

+Statt der langen if-elif-Kette für die einzelnen Funktionen böte sich ein Wörterbuch an.
Das ist eine sehr gute Idee. Die Liste wird vermutlich auch noch wesentlich länger.

-Den Typ einer Variable sollte man nicht in den Namen schreiben, der kann sich nämlich mit der Entwicklung ändern und dann müsste man an allen Stellen die Variable umbenennen.
Ich denke du sprichst von den Variablen gint und gfloat. Das sehe ich nicht so. Der Name ergibt sich aus ihrer Funktion und nicht aus ihrem Typ. Die Funktion von gint ist es, einen "regular expression" für zu speichern, der eine gcode-Ganzzahl beschreibt.
Das bedeutet, die Namen sind so gut und sollen so bleiben.

-def parse_arguments(arguments):
Deine Parse-Funktion muss ich ganz verwerfen. Das schaut vielleicht phytonesk aus, bringt aber nichts. Ersten will ich die Unterscheidung in Vektoren und Skalare haben. Da könnte man natürlich noch eine Schritt ans Ende deiner Funktion anhängen, der dies tut. Also eindimensionale Listen durch durch den Wert ihres einzigen Elements ersetzt. Aber dass du alles auf float konvertierst, das ist nicht sinnvoll. Der Parser soll nicht Informationen verschwinden lassen. Wenn irgendwas als Ganzahl eingegeben wird, dann soll es auch als Ganzzahl gelesen und weitergegeben werden und nicht als Fließkomazahl.
Es wäre auch nicht sinnvoll, zu versuchen einen gelesenen Wert auf int zu konvertieren und wenn dies eine Exception auslöst, zu versuchen den Wert auf float zu konvertieren. Denn nicht Python bestimmt was eine gcode-Ganzzahl bzw. eine gcode-Fließkommazahl ist, sondern die gcode-Syntax. Ich kenne die zwar auch nicht, behaupte aber, dass eine gcode-Ganzzahl das Format "^[+-]?[0-9]+$" und eine gcode-Fliesskommazahl das Format "^[+-]?(([0-9]+\.)|([0-9]*\.[0-9]+))$" hat. Und darum will ich das auch vorher überprüfen. Python würde z.B. auch '1.245E-3' als gültige Fließkommazahl ansehen, gcode (bzw. ich) will das nicht. Glücklicherweise werden alle von mir zugelassenen gcode-Formate auch als gültige Python-Formate anerkannt so dass ich mirt int() bzw. und float() konvertieren kann.

So ende ich schließlich bei folgendem Programm

Code: Alles auswählen

import re

INPUTFILE ='./gcode.txt'

gint=re.compile('^[+-]?[0-9]+$')
gfloat=re.compile('^[+-]?(([0-9]+\.)|([0-9]*\.[0-9]+))$')

def do_G00(var_list):
    print('function G00',var_list)

def do_G01(var_list):
    print('function G01',var_list)

def do_G21(var_list):
    print('function G21',var_list)

def do_G90(var_list):
    print('function G90',var_list)
    
def do_M02(var_list):
    print('function M02',var_list)
    
def do_M03(var_list):
    print('function M03',var_list)
    
def do_M05(var_list):
    print('function M05',var_list)

CMD_TO_FUNC = {
    'G00': do_G00,
    'G01': do_G01,
    'G21': do_G21,
    'G90': do_G90,
    'M02': do_M02,
    'M03': do_M03,
    'M05': do_M05,
}

def parse_arguments(code):
    parts=code.split()
    cmd=parts[0]
    var_dict={}
    arglist=parts[1:]
    for arg in arglist:
        var=arg[:1]
        vals=arg[1:].split(',')
        value_list=[]
        for val in vals:
            if gint.match(val):
                value_list.append(int(val))
            elif gfloat.match(val):
                value_list.append(float(val))
            elif val=='':
                pass
            else:
                raise RuntimeError("value error  %s" % val)
        if not value_list:
            var_dict[var]=None
        elif len(value_list)==1:
            var_dict[var]=value_list[0]
        else:
            var_dict[var]=value_list
    return([cmd,var_dict])
    
with open(INPUTFILE, 'r') as f:
    for line in f:
        line=line.rstrip()
        if line:
            parts=line.split('(')
            code=parts[0]
            if code:
                [cmd,var_dict]=parse_arguments(code)        
                print('line:',line)
                try:
                    func = CMD_TO_FUNC[cmd]
                except KeyError:
                    raise RuntimeError("Unknown command %s" % cmd)
                else:
                    func(var_dict)
                
Hier noch die Testdaten:

Code: Alles auswählen

( This file created by CNC_profile.rb )
( Cutter Diameter: 0.11811023622047245 )
( Stock Size: 4.0551181102362195 x 4.055118110236214 x 0.3937007874015748 )
G21 ( Unit of measure: millimeter )
G90 ( Absolute programming )
M03 ( Spindle on [clockwise] )

G00 Z13,000 F30 (Move safety height)
G00 X0.00 Y.00 F100 ( Move to origin )
G00 X-1,500 Y-1,500 F100
G01 Z0.0 F15
G01 X-1,500 Y-1,500 Z0,000 F50
G01 X-1,500 Y101,500 Z0,000 F50
G01 X101,500 Y101,500 Z0,000 F50
G01 X101,500 Y-1,500 Z0,000 F50
G01 X-1,500 Y-1,500 Z0,000 F50
G00 Z13,000 F30

G00 X0.00 Y.00 F100( Move to origin )
M05 ( Spindle stop )
M02 ( End of program )


G00 Z F30
BlackJack

@miracle173: `contextmanager` ist ein Dekorator. Annotationen sind was anderes und vor allem auch in einer anderen Sprache (Java).

`gint` und `gfloat` sind IMHO keine guten Namen. Ich kann da jedenfalls nicht mal ansatzweise draus erraten das sich dahinter reguläre Ausdrücke für G-Code Werte verbergen. Das sind konstante Werte und `g` ist ein bisschen dürftig um so etwas wie `G_CODE` zu vermitteln. `G_CODE_INT_RE` und `G_CODE_FLOAT_RE` wären IMHO deutlich bessere Namen.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

BlackJack hat geschrieben:@miracle173: `contextmanager` ist ein Dekorator. Annotationen sind was anderes und vor allem auch in einer anderen Sprache (Java).

`gint` und `gfloat` sind IMHO keine guten Namen. Ich kann da jedenfalls nicht mal ansatzweise draus erraten das sich dahinter reguläre Ausdrücke für G-Code Werte verbergen. Das sind konstante Werte und `g` ist ein bisschen dürftig um so etwas wie `G_CODE` zu vermitteln. `G_CODE_INT_RE` und `G_CODE_FLOAT_RE` wären IMHO deutlich bessere Namen.
Ja, die sind wesentlich aussagekräftiger und damit besser.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

miracle173 hat geschrieben:Ziel des Parsers ist es, die Syntax in Python-geeignete Strukturen zu transformieren, ohne all zu viel Wissen über die gcode-Syntax zu wissen.
Genau das ist ja mein Punkt: Der Parser weiß nicht, ob er ein float, ein int, eine Liste von ints erwarten soll. Die Obermenge von allem ist eine Liste mit floats. Der eigentliche Verarbeitungscode kennt dann den geforderten Typ und kann prüfen ob die Liste genau ein int enthält. In Deinem Fall parst der Parser ein int, in Wirklichkeit ist das aber nur ein Spezialfall von einer Liste mit floats, der Verarbeitungscode muß also prüfen, ist das eine Liste oder nicht und wenn nicht, wandle das wieder in eine Liste um. Es ist fast nie eine gute Idee, den Code schlauer zu machen als er eigentlich Information hat.

Ich meinte nicht gint und gfloat, weil beides sind reguläre Ausdrücke und kein int oder float. Ich meinte var_dict, arglist, var_list, value_list.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Sirius3 hat geschrieben: Genau das ist ja mein Punkt: Der Parser weiß nicht, ob er ein float, ein int, eine Liste von ints erwarten soll. Die Obermenge von allem ist eine Liste mit floats.
(...)
Beim Parser kann ich dir nicht beistimmen:

Der Parser weiß nicht, ob er ein float, ein int, eine Liste von ints erwarten soll.
Er weiß zwar nicht was er erwarten soll, aber er weiß, was er bekommen hat
  1. '0', '23', '-1' sind Ganzzahlen
  2. '0.0', '23.456', '.456', '23.', '-.456' sind Gleitkommazahlen
  3. '3,-4' ist ein (2-dimensionaler) Ganzzahlvektor
  4. '2.,-.2' ist ein (2-dimensionaler) Gleitkommavektor
Das alles kann der Parser erkennen.

Ob man für Skalare in einelementige Listen verpackt, mag ja Geschmacksache sein. Allerdings Ganzzahlen als float zu speichern nicht.
  1. Nimm an dein Parser soll arithmetische Ausdrücke parsen und es gilt die übliche C Semantik (die auch möglicherweise bei älteren Pythonversionen noch galt) '/' bedeutet Ganzzahldivision wenn beide Operanden ganzzahlig sind, "normale" Division sonst. Ein Programm mit deinem Parser würde '7/4' als 1.75 auswerten, richtig ist aber 1.
  2. Mag sein das man in der Mathematik die ganzen Zahlen als Untermenge der reellen Zahlen auffassen kann. Die int Zahlen sind aber keineswegs eine Untermenge der float Zahlen

    Code: Alles auswählen

    >>> x='1234567890123456'
    >>> float(x)==int(x)
    True
    >>> x='12345678901234567'
    >>> float(x)==int(x)
    False
    

------------------------------------------------------------------------------------------------------

Allerdings habe ich in der Zwischenzeit nach gcode gegoogelt, z.B.:
http://linuxcnc.org/docs/html/gcode/g-code.html
http://www.cnccookbook.com/GWESampleFiles.html

Ich glaube, dass es in gcode gar keine Vektoren gibt. Eine Zeichenkette '-1,500', wie sie in der Beispieleingabe vorkommt, ist also kein Vektor sondern entweder ein Druckfehler oder ein Komma in einer Zahlendarstellung. Es soll als '-1.500' bedeuten.

Ausserdem scheint es, dass gcode tatsächlich nur float-Zahlen kennt, dass also '123' als '123.0' interpretiert wird.
Antworten