0

I have a simple python script, which reads the serial input and saves it to a file (file.txt). The serial input is like this:{lat: 41.07494, lng:14.2742}, but sometimes there are errors or wrong values, e.g. {lat: 41.▒▒7494, lng:14.2742}, or something else, so the output has to be filtered and than stored to the file.

I tried to use grep with os, but this didnt work, and I dont think it is the proper way to do it in python.

#!/usr/bin/env python

import time
import serial
import os

a = 1
ser = serial.Serial(

 port='/dev/ttyUSB0',
 baudrate = 9600,
 parity=serial.PARITY_NONE,
 stopbits=serial.STOPBITS_ONE,
 bytesize=serial.EIGHTBITS,
 timeout=1
)
counter=0

while 1:
 val=ser.readline()
 print val
 f = open('/file.txt', 'a')
 f.write(val)
 f.close()

 os.system("grep '^{lat: [0-9][8-9]\.[0-9]\{5\}, lng:[0-9][0-9]\.[0-9]\{4\}},$' /file.txt > /filtered.txt")

So the only output should be like this: {lat: xx.xxxxx, lng:xx.xxxxx},

tripleee
  • 175,061
  • 34
  • 275
  • 318
Tim Gelb
  • 17
  • 3
  • Just turn your grep search term into a Python [regex](https://docs.python.org/3/library/re.html#re.compile), and if any line doesn't `match`, throw it out. – 0x5453 Aug 15 '19 at 12:36
  • Do you really mean for these files to be created in the root directory? – tripleee Aug 15 '19 at 12:44
  • Do you really have a space after `lat:` but not after `lng:`? – tripleee Aug 15 '19 at 12:47
  • no its not in the root directory, I changed the path :D Yes there is no space after lng: – Tim Gelb Aug 15 '19 at 13:49
  • I rolled back your latest edit. You really mustn't change your question to a different question entirely after people have spent time on investigating your original problem. Accept one of the answers here and ask a new question if you still need help. – tripleee Aug 15 '19 at 13:57

2 Answers2

0

I would do something like this:

import re
f = open('/file.txt', 'a')

regex = re.compile('^{lat: [0-9][8-9]\.[0-9]\{5\}, lng:[0-9][0-9]\.[0-9]\{4\}},$')
lines_match = list(filter(lambda s: re.match(regex, s), f)
ivallesp
  • 2,018
  • 1
  • 14
  • 21
0

Using an external utility is inconvenient and wasteful anyway; Python has regular expressions in its re library.

You have a number of oddities and antipatterns in your code, but I guess you are looking for something like

import re

# ...
with open('/filtered.txt', 'w') as filtered:
    valid = re.compile(r'^\{lat: [0-9]{2}\.[0-9]{5}, lng:[0-9]{2}\.[0-9]{4}\},$')
    while True:
        val = ser.readline()
        if valid.match(val):
            filtered.write(val)

Notice how the BRE dialect of POSIX grep has the opposite behavior for braces (backslash makes it a metacharacter, without backslash is literal) from Python's re (without backslash is metacharacter, backslash to make it literal) and basically every sane modern dialect.

Your regex would curiously force the second digit of the latitude to be 8 or 9; I assume this was a mistake (your test data would not match). I would also review whether having five decimals for the lat but four for lng is correct (probably require at least four but permit more? [0-9]{4,})

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • wait a sec I ll update the code above. print(repr(val)) prints the following: '' '{lat: 49.10000, lng:10.0000},\r\n' '' '{lat: 49.10000, lng:10.0000},\r\n' '' '{lat: 49.10000, lng:10.0000},\r\n' '' '{lat: 49.10000, lng:10.0000},\r\n' – Tim Gelb Aug 15 '19 at 13:51
  • So you have DOS line endings. Add `\r?` before the `$` in the regex (or fix the line endings to honest to `$dmr` format before applying the regex). – tripleee Aug 15 '19 at 13:52
  • \r? does fix it, now it does match, but it still doesnt get written to the file. – Tim Gelb Aug 15 '19 at 13:57
  • Are you sure? The `\r` will also cause the file to appear munged (as in fact it is). – tripleee Aug 15 '19 at 13:58
  • See also https://stackoverflow.com/questions/39527571/are-shell-scripts-sensitive-to-encoding-and-line-endings (not specific to Python but should give you an idea). – tripleee Aug 15 '19 at 13:59
  • yes filtered.txt is empty, but I get "match" and the correct value printed out. and filtered.txt gets created again, if I deleted manually – Tim Gelb Aug 15 '19 at 14:02
  • and yes i do understaind the problem, but im not sure why there are dos line endings. The serial message comes from an arduino, I have to check this. – Tim Gelb Aug 15 '19 at 14:04
  • Try a hex dump of the file, I'm guessing you are using something which gets confused by the CR characters. These are commonly transmitted over serial lines as well as in DOS text files, but proper handling on Unix would be to filter them out (or not pretend the result is a text file). – tripleee Aug 15 '19 at 14:06
  • Or maybe you are experiencing buffering. The stuff you write out to a file is buffered for a while and if you are examining the file while it's still open you might not yet see the contents which will be written there eventually. Try flushing the handle after writing if buffering is unacceptable. – tripleee Aug 15 '19 at 14:08
  • Again, this is based on guessing what you want, because you have not spelled out in your question what you hope for the code to actually do. And again, if you still need help, I think we can say your regex question is solved, so perhaps accept one of the answers here (post one of your own if you like) and maybe ask a new question if you are wondering about other things around this. – tripleee Aug 15 '19 at 14:09
  • well I got it working like so, and ignoring the dos endings, hopefully: if valid.match(val): print(val) print("match") f = open("/home/pi/filtered.txt", "a") f.write(val) f.close – Tim Gelb Aug 15 '19 at 14:10
  • Opening the file for appending every time you want to write something is pretty inefficient, keeping it open throughout and adding an explicit flush would probably be better. – tripleee Aug 15 '19 at 14:13
  • I need the file for a php script, so I thought I have to close. right? – Tim Gelb Aug 15 '19 at 14:16
  • Then the `while True` is not really correct, is it? – tripleee Aug 15 '19 at 14:17
  • why do you think its not? I want to get live values – Tim Gelb Aug 15 '19 at 14:18
  • Flushing is enough, but then how do you pass only new data to PHP? Maybe use a pipe instead (have Python print to standard output, and PHP read from standard input.) – tripleee Aug 15 '19 at 14:34
  • well that is not a problem, I dont want to get new data only – Tim Gelb Aug 15 '19 at 14:37