2

I have this kind of file (part):

H DX=615 DY=425 DZ=22.15 -AB C=0 T=0 R=999 *MM /"def" BX=2.5 BY=452.5 BZ=25 ;M20150710.

XBO X=100 Y=50 Z=5 V=1000 R=0 x=0 y=0 D=10 N="P" F=1 ;Test F1/10P.

...

which I want to convert to a new programming system. What I want to do is first read the header (H) and put the DX, DY and DZ values in respectively named variables. I managed to do this, but when I came to process my XBO line (a drilling, from which I need X, Y, Z, V, R, x, y, D, N, F and ;, also in separate variables) my code started looking very ugly very fast.

So I started over, and came up with this:

f = open("input.xxl") # open input file
for line in f:
    if Debug==1: print line
    for char in line:
        charbuffr=charbuffr+char
        if "H" in charbuffr:
            if Debug==1: print'HEADER found!'
            charbuffr=""           
        if "XBO" in charbuffr:
            if Debug==1: print'XBO found!'
            charbuffr=""       

This correctly identifies the separate commands H and XBO, but I'm kind of stuck now. I can use the same method to extract all the variables, from loops inside the H and XBO loops, but this does not seem like good coding...

Can anyone set me on the right foot please? I don't want a full solution, as I love coding (well my main job is coding for CNC machines, which seems easy now compared to Python), but would love to know which approach is best...

Michel Storms
  • 336
  • 3
  • 10

2 Answers2

1

As an inspiration, you can do something like this:

for raw_line in f:
    line = raw_line.split()
    if not line:
        continue
    if line[0] == 'H':
        header = {}
        for entry in line[1:4]:
            name, value = entry.split('=')
            header[name] = float(value)
    elif line[0] == 'XBO':
        xbo = {}
        for entry in line[1:11]:
            name, value = entry.split('=')
            try:
                xbo[name] = int(value)
            except ValueError:
                xbo[name] = value[1:-1] # stripping of the ""

Now headercontains the extensions of your domain:

{'DX': 615.0, 'DY': 425.0, 'DZ': 22.15}

and xbo the other values:

{'D': 10,
 'F': 1,
 'N': 'P',
 'R': 0,
 'V': 1000,
 'X': 100,
 'Y': 50,
 'Z': 5,
 'x': 0,
 'y': 0}

Access the individual values in the dictionaries:

>>> header['DX']
615.0
Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Thanks all for the awesome answers! Can continue with my project now :). – Michel Storms Dec 05 '15 at 12:49
  • You can [accept](http://stackoverflow.com/help/accepted-answer) an answer if it solves your problem. – Mike Müller Dec 05 '15 at 12:50
  • Ok will have to look how to do that first :). Your answer DID solve the problem and opened a lot of other possibilities for the program that I didn't even think of at first... – Michel Storms Dec 05 '15 at 17:57
  • Hi, changed these : #header[name] = float(value) > header[name] = str(value)int(value) #xbo[name] = xbo[name] = str(value) to be able to also process lines like this: 'XBO X=DX-100'. Do you see any problem with it? It does seem to work, but it was too easy and I think there's gonna be a catch later on in my code because of this... Thanks! – Michel Storms Dec 07 '15 at 04:59
1

Instead of converting data types by hand, you could use ast. literal_eval. This helper function takes a list of the form ['a=2', 'b="abc"'] and converts into a dictionary {'a': 2, 'b': 'abc'}:

import ast

def dict_from_row(row):
    """Convert a list of strings in the form 'name=value' into a dict."""
    res = []
    for entry in row:
        name, value = entry.split('=')
        res.append('"{name}": {value}'.format(name=name, value=value))
    dict_string = '{{{}}}'.format(', '.join(res))
    return ast.literal_eval(dict_string)

Now parsing the file becomes a bit simpler:

for line in f:
    row = line.split()
    if not row:
        continue
    if row[0] == 'H':
        header = dict_from_row(row[1:4])
    elif line[0] == 'XBO':
        xbo = dict_from_row(row[1:11])

Results:

>>> header
{'DX': 615, 'DY': 425, 'DZ': 22.15}

>>> xbo
{'D': 10, 'F': 1, 'R': 0, 'V': 1000, 'X': 100, 'Y': 50, 'Z': 5, 'x': 0, 'y': 0}
Mike Müller
  • 82,630
  • 20
  • 166
  • 161