Textbox.edit() inputs letters twice - python

I wrote simple function, and I can't figure out why it inputs letters twice. I was trying to change position of screen.refresh(), but the problem is, this screen isn't reloading, after choosing this function from menu.
def add_dish():
screen.clear()
screen.border('|', '|', '-', '-', '+', '+', '+', '+')
screen.addstr(2, 50, "Add dish to catalog")
screen.addstr(4, 4, "Dish: ")
win = curses.newwin(1,30,4,10)
box = Textbox(win)
screen.refresh()
box.edit()
screen.getch()
Main function look like this (it's in polish, but it doesn't really matter)
def main():
maxY, maxX = screen.getmaxyx()
maxY = int(maxY)
maxX = int(round(maxX))
ticker = 3
screen.clear()
screen.border('|', '|', '-', '-', '+', '+', '+', '+')
screen.addstr(2, 35, "Witaj w katalogu wyności, który przedstawi Ci potrawy i ich kalorie w 100g!")
screen.addstr(3,50, "Poniej przedstawione są mozliwe opcje.")
screen.addstr(6, 10, "1. Wyświetl zawartość katalogu")
screen.addstr(7, 10, "2. Dodaj do katalogu")
screen.addstr(8, 10, "3. Usuń z katalogu")
screen.addstr(9, 10, "4. Znajdź i wyświetl dane danie")
screen.addstr(10, 10, "5. Znajdź i wyświetl danie po wartości")
screen.addstr(11, 10, "6. Zakończ działanie aplikacji")
key = screen.getch()
if key == ord("1"):
wyswietl_katalog(ticker, maxY, maxX)
elif key == ord("2"):
add_dish()
screen.refresh()

Related

How to track movement of a single chess piece?

I'm using python-chess and I would like to know what is a good way to track movement of let say a black King throughout a single match recorded in pgn format using python-chess. Essentially creating a string of every position it achieved.
Sample code to record black king squares, moves epd etc.
Code
import chess.pgn
# Save position of black king in each game.
data = []
pgnfile = "mygame.pgn"
gcnt = 0
with open(pgnfile) as pgn:
while True:
game = chess.pgn.read_game(pgn)
if game is None:
break
gcnt += 1
sqnames = []
sqvalues = []
epds = []
sanmoves = []
ucimoves = []
# first entry of moves is null move
sanmoves.append(str(chess.Move.null()))
ucimoves.append(str(chess.Move.null()))
# Save the first location of king.
b = game.board()
sqnames.append(chess.square_name(b.king(chess.BLACK)))
sqvalues.append(b.king(chess.BLACK))
epds.append(b.epd())
for node in game.mainline(): # parse nodes in this game
board = node.board()
m = node.move
tosq = m.to_square
p = board.piece_at(tosq)
if p.piece_type == chess.KING and p.color == chess.BLACK:
sqnames.append(chess.square_name(tosq))
sqvalues.append(tosq)
epds.append(board.epd())
sanmoves.append(node.parent.board().san(m))
ucimoves.append(node.parent.board().uci(m))
data.append({'game': gcnt, 'sqnames': sqnames, 'sqvalues': sqvalues, 'epd': epds, 'sanmoves': sanmoves, 'ucimoves': ucimoves})
if gcnt >= 10: # sample limit
break
# Print tracks of king per game.
for d in data:
print(d)
Output
{'game': 1, 'sqnames': ['e8', 'g8'], 'sqvalues': [60, 62], 'epd': ['rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -', 'r2q1rk1/p2bbppp/2pppn2/6B1/3NP3/2NQ4/PPP2PPP/2KR3R w - -'], 'sanmoves': ['0000', 'O-O'], 'ucimoves': ['0000', 'e8g8']}
{'game': 2, 'sqnames': ['e8', 'd7', 'e8', 'f8'], 'sqvalues': [60, 51, 60, 61], 'epd': ['rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -', 'rn5r/pp1k1p1p/4bp2/1N2p3/1b6/1N3P2/PPP3PP/R2K1B1R w - -', 'rnr1k3/pp2bp1p/4b3/1N2pp2/8/PN1B1P2/1PP2KPP/R6R w - -', 'r1r2k2/pp1nbp1p/4b3/4pp2/8/PNNB1P2/1PP2KPP/R3R3 w - -'], 'sanmoves': ['0000', 'Kd7', 'Ke8', 'Kf8'], 'ucimoves': ['0000', 'e8d7', 'd7e8', 'e8f8']}

itertools.product using list comprehension

I want to use list comprehension, instead of itertools.product
def pr(l):
return [''.join(i) for i in [(x,y) for x in l for y in l]]
operators = ['/','*','+','-']
pr(operators)
['//', '/*', '/+', '/-', '*/', '**', '*+', '*-', '+/', '+*', '++', '+-', '-/', '-*', '-+', '--']
This works, but I want to modify my function such that it returns combinations in pairs of repeat:
def pr(l, repeat=1):
# list comprehension code here
o = ['/','*','+','-']
pr(operators, repeat=4)
pr(operators, repeat=3)
['////', '///*', '///+', '///-', '//*/', '//**', '//*+', '//*-', '//+/', '//+*', '//++', '//+-', '//-/', '//-*', '//-+', '//--', '/*//', '/*/*', '/*/+', '/*/-', '/**/', '/***', '/**+', '/**-', '/*+/', '/*+*', '/*++', '/*+-', '/*-/', '/*-*', '/*-+', '/*--', '/+//', '/+/*', '/+/+', '/+/-', '/+*/', '/+**', '/+*+', '/+*-', '/++/', '/++*', '/+++', '/++-', '/+-/', '/+-*', '/+-+', '/+--', '/-//', '/-/*', '/-/+', '/-/-', '/-*/', '/-**', '/-*+', '/-*-', '/-+/', '/-+*', '/-++', '/-+-', '/--/', '/--*', '/--+', '/---', '*///', '*//*', '*//+', '*//-', '*/*/', '*/**', '*/*+', '*/*-', '*/+/', '*/+*', '*/++', '*/+-', '*/-/', '*/-*', '*/-+', '*/--', '**//', '**/*', '**/+', '**/-', '***/', '****', '***+', '***-', '**+/', '**+*', '**++', '**+-', '**-/', '**-*', '**-+', '**--', '*+//', '*+/*', '*+/+', '*+/-', '*+*/', '*+**', '*+*+', '*+*-', '*++/', '*++*', '*+++', '*++-', '*+-/', '*+-*', '*+-+', '*+--', '*-//', '*-/*', '*-/+', '*-/-', '*-*/', '*-**', '*-*+', '*-*-', '*-+/', '*-+*', '*-++', '*-+-', '*--/', '*--*', '*--+', '*---', '+///', '+//*', '+//+', '+//-', '+/*/', '+/**', '+/*+', '+/*-', '+/+/', '+/+*', '+/++', '+/+-', '+/-/', '+/-*', '+/-+', '+/--', '+*//', '+*/*', '+*/+', '+*/-', '+**/', '+***', '+**+', '+**-', '+*+/', '+*+*', '+*++', '+*+-', '+*-/', '+*-*', '+*-+', '+*--', '++//', '++/*', '++/+', '++/-', '++*/', '++**', '++*+', '++*-', '+++/', '+++*', '++++', '+++-', '++-/', '++-*', '++-+', '++--', '+-//', '+-/*', '+-/+', '+-/-', '+-*/', '+-**', '+-*+', '+-*-', '+-+/', '+-+*', '+-++', '+-+-', '+--/', '+--*', '+--+', '+---', '-///', '-//*', '-//+', '-//-', '-/*/', '-/**', '-/*+', '-/*-', '-/+/', '-/+*', '-/++', '-/+-', '-/-/', '-/-*', '-/-+', '-/--', '-*//', '-*/*', '-*/+', '-*/-', '-**/', '-***', '-**+', '-**-', '-*+/', '-*+*', '-*++', '-*+-', '-*-/', '-*-*', '-*-+', '-*--', '-+//', '-+/*', '-+/+', '-+/-', '-+*/', '-+**', '-+*+', '-+*-', '-++/', '-++*', '-+++', '-++-', '-+-/', '-+-*', '-+-+', '-+--', '--//', '--/*', '--/+', '--/-', '--*/', '--**', '--*+', '--*-', '--+/', '--+*', '--++', '--+-', '---/', '---*', '---+', '----']
['///', '//*', '//+', '//-', '/*/', '/**', '/*+', '/*-', '/+/', '/+*', '/++', '/+-', '/-/', '/-*', '/-+', '/--', '*//', '*/*', '*/+', '*/-', '**/', '***', '**+', '**-', '*+/', '*+*', '*++', '*+-', '*-/', '*-*', '*-+', '*--', '+//', '+/*', '+/+', '+/-', '+*/', '+**', '+*+', '+*-', '++/', '++*', '+++', '++-', '+-/', '+-*', '+-+', '+--', '-//', '-/*', '-/+', '-/-', '-*/', '-**', '-*+', '-*-', '-+/', '-+*', '-++', '-+-', '--/', '--*', '--+', '---']
How can I do that?
Here's a generic solution for any value of 'repeat'.
def pr(l, repeat=1):
if repeat == 1:
return [[x] for x in l]
sub_prod = pr(l, repeat-1)
return [ [x] + y for x in l for y in sub_prod ]
o = ['/','*','+','-']
pr(o, 3)
Result:
[['/', '/', '/'],
['/', '/', '*'],
['/', '/', '+'],
['/', '/', '-'],
['/', '*', '/'],
['/', '*', '*'],
['/', '*', '+'],
['/', '*', '-'],
['/', '+', '/'],
['/', '+', '*'],
['/', '+', '+'],
...
If you want to turn each sublist to a string, use:
["".join(x) for x in pr(o, 3)]
Just wrap your command in a function
def f(l):
return [(x, y) for x in l for y in l]
or if you want the same generator behavior as itertools has:
def f(l):
return ((x, y) for x in l for y in l)
or a more verbose generator syntax:
def f(l):
for x in l:
for y in l:
yield x, y

How to change value in list for calendar?

The goal of my function is to book a slot in that calendar corresponding to the parameters day and time - booking is done by changing the value in the calendar to “X” (to indicate that day/time is booked). Here is the code I have so far:
def find_index(val, seq):
for index in range(len(seq)):
place = seq[index]
if place == val:
return index
else:
return int("-1")
def init_nested_list(size_outer, size_inner):
cal = []
for outer_index in range(size_outer):
nested_list = []
for inner_index in range(size_inner):
nested_list.append("-")
cal.append(nested_list)
return cal
def book_slot(cal,days_labels, times_labels, day, time):
pos1 = find_index(day, days_labels)
desired_day = cal[pos1]
pos2 = find_index(time, times_labels)
desired_time = desired_day[pos2]
if desired_day == "X":
print("We are sorry - that time is not available. Please try again.")
else:
print("Appointment is booked.")
days_labels = ["Wednesday","Thursday","Friday"]
times_labels = ["9","10","11"]
cal = init_nested_list(len(days_labels), len(times_labels))
print("before" , cal)
book_slot(cal, days_labels, times_labels, "Friday", "10")
print("after" , cal)
This is the output I'm getting:
before [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
Appointment is booked.
after [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
This is the output I should be getting:
before [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
Appointment is booked.
after [['-', '-', '-'], ['-', '-', '-'], ['-', 'X', '-']]
We are sorry - that time is not available. Please try again.
As you can see, the correct output books the second element in the nested list(Friday at 10), but for my code it is not. I know desired_day is the day in cal that the user wants to book, but I'm just unsure of how to properly obtain that, and assign it to the string "X" when it is booked by the user. I also know that there is a coding error in the book_slot function that is causing this, but once again, I'm just unsure what it is...help please?
Nowhere in book_slot do you assign X to anything. I should think you could use pos1 and pos2 to identify the slot to assign to.
This will work. See the Change # notes in the code
def find_index(val, seq):
return seq.index(val) #Change 1
def init_nested_list(size_outer, size_inner):
cal = []
for outer_index in range(size_outer):
nested_list = []
for inner_index in range(size_inner):
nested_list.append("-")
cal.append(nested_list)
return cal
def book_slot(cal, days_labels, times_labels, day, time):
pos1 = find_index(day, days_labels)
desired_day = cal[pos1]
pos2 = find_index(time, times_labels)
if desired_day[pos2] is "X": # Change 2
print("We are sorry - that time is not available. Please try again.")
else:
print("Appointment is booked.")
desired_day[pos2] = "X" # Change 3
days_labels = ["Wednesday", "Thursday", "Friday"]
times_labels = ["9", "10", "11"]
cal = init_nested_list(len(days_labels), len(times_labels))
print("before", cal)
book_slot(cal, days_labels, times_labels, "Friday", "10")
book_slot(cal, days_labels, times_labels, "Friday", "10") # Change 4: Need to do a booking twice to make it fail :-)
print("after", cal)
will output:
('before', [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']])
Appointment is booked.
('after', [['-', '-', '-'], ['-', '-', '-'], ['-', 'X', '-']])
We are sorry - that time is not available. Please try again.

How can I split a string of a mathematical expressions in python?

I made a program which convert infix to postfix in python. The problem is when I introduce the arguments.
If i introduce something like this: (this will be a string)
( ( 73 + ( ( 34 - 72 ) / ( 33 - 3 ) ) ) + ( 56 + ( 95 - 28 ) ) )
it will split it with .split() and the program will work correctly.
But I want the user to be able to introduce something like this:
((73 + ( (34- 72 ) / ( 33 -3) )) + (56 +(95 - 28) ) )
As you can see I want that the blank spaces can be trivial but the program continue splitting the string by parentheses, integers (not digits) and operands.
I try to solve it with a for but I don't know how to catch the whole number (73 , 34 ,72) instead one digit by digit (7, 3 , 3 , 4 , 7 , 2)
To sum up, what I want is split a string like ((81 * 6) /42+ (3-1)) into:
[(, (, 81, *, 6, ), /, 42, +, (, 3, -, 1, ), )]
Tree with ast
You could use ast to get a tree of the expression :
import ast
source = '((81 * 6) /42+ (3-1))'
node = ast.parse(source)
def show_children(node, level=0):
if isinstance(node, ast.Num):
print(' ' * level + str(node.n))
else:
print(' ' * level + str(node))
for child in ast.iter_child_nodes(node):
show_children(child, level+1)
show_children(node)
It outputs :
<_ast.Module object at 0x7f56abbc5490>
<_ast.Expr object at 0x7f56abbc5350>
<_ast.BinOp object at 0x7f56abbc5450>
<_ast.BinOp object at 0x7f56abbc5390>
<_ast.BinOp object at 0x7f56abb57cd0>
81
<_ast.Mult object at 0x7f56abbd0dd0>
6
<_ast.Div object at 0x7f56abbd0e50>
42
<_ast.Add object at 0x7f56abbd0cd0>
<_ast.BinOp object at 0x7f56abb57dd0>
3
<_ast.Sub object at 0x7f56abbd0d50>
1
As #user2357112 wrote in the comments : ast.parse interprets Python syntax, not mathematical expressions. (1+2)(3+4) would be parsed as a function call and list comprehensions would be accepted even though they probably shouldn't be considered a valid mathematical expression.
List with a regex
If you want a flat structure, a regex could work :
import re
number_or_symbol = re.compile('(\d+|[^ 0-9])')
print(re.findall(number_or_symbol, source))
# ['(', '(', '81', '*', '6', ')', '/', '42', '+', '(', '3', '-', '1', ')', ')']
It looks for either :
multiple digits
or any character which isn't a digit or a space
Once you have a list of elements, you could check if the syntax is correct, for example with a stack to check if parentheses are matching, or if every element is a known one.
You need to implement a very simple tokenizer for your input. You have the following types of tokens:
(
)
+
-
*
/
\d+
You can find them in your input string separated by all sorts of white space.
So a first step is to process the string from start to finish, and extract these tokens, and then do your parsing on the tokens, rather than on the string itself.
A nifty way to do this is to use the following regular expression: '\s*([()+*/-]|\d+)'. You can then:
import re
the_input='(3+(2*5))'
tokens = []
tokenizer = re.compile(r'\s*([()+*/-]|\d+)')
current_pos = 0
while current_pos < len(the_input):
match = tokenizer.match(the_input, current_pos)
if match is None:
raise Error('Syntax error')
tokens.append(match.group(1))
current_pos = match.end()
print(tokens)
This will print ['(', '3', '+', '(', '2', '*', '5', ')', ')']
You could also use re.findall or re.finditer, but then you'd be skipping non-matches, which are syntax errors in this case.
If you don't want to use re module, you can try this:
s="((81 * 6) /42+ (3-1))"
r=[""]
for i in s.replace(" ",""):
if i.isdigit() and r[-1].isdigit():
r[-1]=r[-1]+i
else:
r.append(i)
print(r[1:])
Output:
['(', '(', '81', '*', '6', ')', '/', '42', '+', '(', '3', '-', '1', ')', ')']
It actual would be pretty trivial to hand-roll a simple expression tokenizer. And I'd think you'd learn more that way as well.
So for the sake of education and learning, Here is a trivial expression tokenizer implementation which can be extended. It works based upon the "maximal-much" rule. This means it acts "greedy", trying to consume as many characters as it can to construct each token.
Without further ado, here is the tokenizer:
class ExpressionTokenizer:
def __init__(self, expression, operators):
self.buffer = expression
self.pos = 0
self.operators = operators
def _next_token(self):
atom = self._get_atom()
while atom and atom.isspace():
self._skip_whitespace()
atom = self._get_atom()
if atom is None:
return None
elif atom.isdigit():
return self._tokenize_number()
elif atom in self.operators:
return self._tokenize_operator()
else:
raise SyntaxError()
def _skip_whitespace(self):
while self._get_atom():
if self._get_atom().isspace():
self.pos += 1
else:
break
def _tokenize_number(self):
endpos = self.pos + 1
while self._get_atom(endpos) and self._get_atom(endpos).isdigit():
endpos += 1
number = self.buffer[self.pos:endpos]
self.pos = endpos
return number
def _tokenize_operator(self):
operator = self.buffer[self.pos]
self.pos += 1
return operator
def _get_atom(self, pos=None):
pos = pos or self.pos
try:
return self.buffer[pos]
except IndexError:
return None
def tokenize(self):
while True:
token = self._next_token()
if token is None:
break
else:
yield token
Here is a demo the usage:
tokenizer = ExpressionTokenizer('((81 * 6) /42+ (3-1))', {'+', '-', '*', '/', '(', ')'})
for token in tokenizer.tokenize():
print(token)
Which produces the output:
(
(
81
*
6
)
/
42
+
(
3
-
1
)
)
Quick regex answer:
re.findall(r"\d+|[()+\-*\/]", str_in)
Demonstration:
>>> import re
>>> str_in = "((81 * 6) /42+ (3-1))"
>>> re.findall(r"\d+|[()+\-*\/]", str_in)
['(', '(', '81', '*', '6', ')', '/', '42', '+', '(', '3', '-', '1',
')', ')']
For the nested parentheses part, you can use a stack to keep track of the level.
This does not provide quite the result you want but might be of interest to others who view this question. It makes use of the pyparsing library.
# Stolen from http://pyparsing.wikispaces.com/file/view/simpleArith.py/30268305/simpleArith.py
# Copyright 2006, by Paul McGuire
# ... and slightly altered
from pyparsing import *
integer = Word(nums).setParseAction(lambda t:int(t[0]))
variable = Word(alphas,exact=1)
operand = integer | variable
expop = Literal('^')
signop = oneOf('+ -')
multop = oneOf('* /')
plusop = oneOf('+ -')
factop = Literal('!')
expr = operatorPrecedence( operand,
[("!", 1, opAssoc.LEFT),
("^", 2, opAssoc.RIGHT),
(signop, 1, opAssoc.RIGHT),
(multop, 2, opAssoc.LEFT),
(plusop, 2, opAssoc.LEFT),]
)
print (expr.parseString('((81 * 6) /42+ (3-1))'))
Output:
[[[[81, '*', 6], '/', 42], '+', [3, '-', 1]]]
Using grako:
start = expr $;
expr = calc | value;
calc = value operator value;
value = integer | "(" #:expr ")" ;
operator = "+" | "-" | "*" | "/";
integer = /\d+/;
grako transpiles to python.
For this example, the return value looks like this:
['73', '+', ['34', '-', '72', '/', ['33', '-', '3']], '+', ['56', '+', ['95', '-', '28']]]
Normally you'd use the generated semantics class as a template for further processing.
To provide a more verbose regex approach that you could easily extend:
import re
solution = []
pattern = re.compile('([\d\.]+)')
s = '((73 + ( (34- 72 ) / ( 33 -3) )) + (56 +(95 - 28) ) )'
for token in re.split(pattern, s):
token = token.strip()
if re.match(pattern, token):
solution.append(float(token))
continue
for character in re.sub(' ', '', token):
solution.append(character)
Which will give you the result:
solution = ['(', '(', 73, '+', '(', '(', 34, '-', 72, ')', '/', '(', 33, '-', 3, ')', ')', ')', '+', '(', 56, '+', '(', 95, '-', 28, ')', ')', ')']
Similar to #McGrady's answer, you can do this with a basic queue implementation.
As a very basic implementation, here's what your Queue class can look like:
class Queue:
EMPTY_QUEUE_ERR_MSG = "Cannot do this operation on an empty queue."
def __init__(self):
self._items = []
def __len__(self) -> int:
return len(self._items)
def is_empty(self) -> bool:
return len(self) == 0
def enqueue(self, item):
self._items.append(item)
def dequeue(self):
try:
return self._items.pop(0)
except IndexError:
raise RuntimeError(Queue.EMPTY_QUEUE_ERR_MSG)
def peek(self):
try:
return self._items[0]
except IndexError:
raise RuntimeError(Queue.EMPTY_QUEUE_ERR_MSG)
Using this simple class, you can implement your parse function as:
def tokenize_with_queue(exp: str) -> List:
queue = Queue()
cum_digit = ""
for c in exp.replace(" ", ""):
if c in ["(", ")", "+", "-", "/", "*"]:
if cum_digit != "":
queue.enqueue(cum_digit)
cum_digit = ""
queue.enqueue(c)
elif c.isdigit():
cum_digit += c
else:
raise ValueError
if cum_digit != "": #one last sweep in case there are any digits waiting
queue.enqueue(cum_digit)
return [queue.dequeue() for i in range(len(queue))]
Testing it like below:
exp = "((73 + ( (34- 72 ) / ( 33 -3) )) + (56 +(95 - 28) ) )"
print(tokenize_with_queue(exp)")
would give you the token list as:
['(', '(', '73', '+', '(', '(', '34', '-', '72', ')', '/', '(', '33', '-', '3', ')', ')', ')', '+', '(', '56', '+', '(', '95', '-', '28', ')', ')', ')']

How to parse lines in file in sequence/match adequate results using python, pyparsing?

Here's my code:
from pyparsing import *
survey ='''
BREAK_L,PN1000,LA55.16469813,LN18.15054629
PN1,LA54.16469813,LN17.15054629,EL22.222
BREAK_L,PN2000,LA55.16507249,LN18.15125566
PN6,LA54.16506873,LN17.15115798,EL33.333
PN7,LA54.16507249,LN17.15125566,EL44.444
BREAK_L,PN3000,LA55.16507249,LN18.15125566
PN10,LA54.16507522,LN17.15198405,EL55.555
PN11,LA54.16506566,LN17.15139220,EL44.44
PN12,LA54.16517275,LN17.15100652,EL11.111
'''
digits = "0123456789"
number = Word(nums+'.').setParseAction(lambda t: float(t[0]))
num = Word(digits)
text = Word(alphas)
pt_id = Suppress('PN') + Combine(Optional(text) + num + Optional(text) + Optional(num))
separator = Suppress(',')
latitude = Suppress('LA') + number
longitude = Suppress('LN') + number
gps_line = pt_id + separator + latitude + separator + longitude
break_line = (Suppress('BREAK_L,')
+ pt_id
+ separator
+ latitude
+ separator
+ longitude)
result1 = gps_line.scanString(survey)
result2 = break_line.scanString(survey)
for item in result1:
print item
With example above I would like to find solution how to get output like:
gps_line + it's break_line, what means something like in pseudo code:
for every gps_line in result1:
print gps_line + precedent break_line
If matter of my question is not clear or not fit to description, feel free to change it.
EDIT #2
What I try to achieve is output:
['1', 54.16469813, 17.15054629, 22.222, 'BP1000', 55.16469813, 18.15054629]
['6', 54.16506873, 17.15115798, 33.333, 'BP2000', 55.16507249, 18.15125566]
['7', 54.16507249, 17.15125566, 44.444, 'BP2000', 55.16507249, 18.15125566]
['10', 54.16507522, 17.15198405, 55.555, 'BP3000', 55.16507249, 18.15125566]
['11', 54.16506566, 17.1513922, 44.44, 'BP3000', 55.16507249, 18.15125566]
['12', 54.16517275, 17.15100652, 11.111, 'BP3000', 55.16507249, 18.15125566]
Second attempt:
from decimal import Decimal
from operator import itemgetter
survey ='''
BREAK_L,PN1000,LA55.16469813,LN18.15054629
PN1,LA54.16469813,LN17.15054629,EL22.222
BREAK_L,PN2000,LA55.16507249,LN18.15125566
PN6,LA54.16506873,LN17.15115798,EL33.333
PN7,LA54.16507249,LN17.15125566,EL44.444
BREAK_L,PN3000,LA55.16507249,LN18.15125566
PN10,LA54.16507522,LN17.15198405,EL55.555
PN11,LA54.16506566,LN17.15139220,EL44.44
PN12,LA54.16517275,LN17.15100652,EL11.111
'''
def parse_line(line):
brk = False
kv = {}
for part in line.split(','):
if part == 'BREAK_L':
brk = True
else:
k = part[:2]
v = part[2:]
kv[k] = v
return (brk,kv)
def parse_survey(survey):
ig1 = itemgetter('PN','LA','LN','EL')
ig2 = itemgetter('PN','LA','LN')
brk_data = None
for line in survey.strip().splitlines():
brk, data = parse_line(line)
if brk:
brk_data = data
continue
else:
yield ig1(data) + ig2(brk_data)
for r in parse_survey(survey):
print r
Yields:
('1', '54.16469813', '17.15054629', '22.222', '1000', '55.16469813', '18.15054629')
('6', '54.16506873', '17.15115798', '33.333', '2000', '55.16507249', '18.15125566')
('7', '54.16507249', '17.15125566', '44.444', '2000', '55.16507249', '18.15125566')
('10', '54.16507522', '17.15198405', '55.555', '3000', '55.16507249', '18.15125566')
('11', '54.16506566', '17.15139220', '44.44', '3000', '55.16507249', '18.15125566')
('12', '54.16517275', '17.15100652', '11.111', '3000', '55.16507249', '18.15125566')
This is really not much different to my previous attempt. I'd already paired the data for you. I assume you'll be able to change 1000 into BP1000 yourself.

Categories