[英]Find string between two substrings AND between string and the end of file
[英]Find string between two substrings, in a stream of data
我有这个连续的串行数据 stream:
----------------------------------------
SENSOR COORDINATE = 0
MEASURED RESISTANCE = 3.70 kOhm
----------------------------------------
----------------------------------------
SENSOR COORDINATE = 1
MEASURED RESISTANCE = 3.70 kOhm
----------------------------------------
----------------------------------------
SENSOR COORDINATE = 2
MEASURED RESISTANCE = 3.69 kOhm
----------------------------------------
对于每次迭代,我希望能够获取值。 传感器坐标值和电阻值。
我找到了使用.split()
和使用正则表达式( 在两个子字符串之间查找字符串)的解决方案,但问题是在我的情况下,我想要过滤的不是一个字符串,而是一个连续的 stream。
例如, .split()
会找到我的字符串,但它会将 stream 分成两半。 这不起作用,在连续的 stream 中,不止一次。
注意:在传感器坐标值之后,我有一个回车符。
编辑 1/3:这是获取串行数据的代码片段:
def readSerial():
global after_id
while ser.in_waiting:
try:
ser_bytes = ser.readline() #read data from the serial line
ser_bytes = ser_bytes.decode("utf-8")
text.insert("end", ser_bytes)
except UnicodeDecodeError:
print("UnicodeDecodeError")
else:
print("No data received")
after_id=root.after(50,readSerial)
如果有人想知道,这是 arduino 端的 C 代码,它发送数据:
Serial.println("----------------------------------------");
Serial.print("SENSOR COORDINATE = ");
Serial.println(sensor_coord);
Serial.print("MEASURED RESISTANCE = ");
double resistanse = ((period * GAIN_VALUE * 1000) / (4 * CAPACITOR_VALUE)) - R_BIAS_VALUE;
Serial.print(resistanse);
Serial.println(" kOhm");
编辑 2/3:这是以前的方法:
def readSerial():
global after_id
while ser.in_waiting:
try:
ser_bytes = ser.readline() #read data from the serial line
ser_bytes = ser_bytes.decode("utf-8")
text.insert("end", ser_bytes)
result = re.search.(, ser_bytes)
print(result)
except UnicodeDecodeError:
print("UnicodeDecodeError")
else:
print("No data received")
after_id=root.after(50,readSerial)
在另一次尝试中,我将这一行result = re.search.(, ser_bytes)
更改为result =ser_bytes.split("TE = ")
。
这是我收到的数据的图片(这是一个 tkinter 文本框)。
编辑 3/3:这是我实现 dracarys 算法的代码:
def readSerial():
global after_id
while ser.in_waiting:
try:
ser_bytes = ser.readline()
print(ser_bytes)
ser_bytes = ser_bytes.decode("utf-8")
print(ser_bytes)
text.insert("end", ser_bytes)
if "SENSOR COORDINATE" in ser_bytes:
found_coordinate = True
coordinate = int(ser_bytes.split("=")[1].strip())
print("Coordinate",coordinate)
if "MEASURED RESISTANCE" in ser_bytes and found_coordinate:
found_coordinate = False
resistance = float(ser_bytes.split("=")[1].split("kOhm")[0].strip())
print("Resistance",resistance)
except UnicodeDecodeError:
print("UnicodeDecodeError")
else:
print("No data received")
after_id=root.after(50,readSerial)
这是我得到的错误,在代码成功运行大约十秒钟后(我已经包括正常操作 output 以及参考):
No data received
b'SENSOR COORDINATE = 2\r\n'
SENSOR COORDINATE = 2
Coordinate 2
b'MEASURED RESISTANCE = 3.67 kOhm\r\n'
MEASURED RESISTANCE = 3.67 kOhm
Resistance 3.67
b'----------------------------------------\r\n'
----------------------------------------
b'----------------------------------------\r\n'
----------------------------------------
b'SENSOR COORDINATE = 3\r\n'
SENSOR COORDINATE = 3
Coordinate 3
No data received
b'MEASURED RESISTANCE = 3.78 kOhm\r\n'
MEASURED RESISTANCE = 3.78 kOhm
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\User1\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__i
nit__.py", line 1883, in __call__
return self.func(*args)
File "C:\Users\User1\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__i
nit__.py", line 804, in callit
func(*args)
File "tkinterWithPortsExperiment.py", line 73, in readSerial
if "MEASURED RESISTANCE" in ser_bytes and found_coordinate:
UnboundLocalError: local variable 'found_coordinate' referenced before assignment
正如我在评论中所说,我觉得 Arduino output 应该简化。 正如@oliver_t 所说,每个传感器事件的单行 JSON 将是完美的。
如果你不能这样做,这里是解析这个的代码。
由于我没有任何方式逐行接收您的串行监视器 output,因此我通过将 output 存储在 txt 文件中然后逐行读取来进行模拟。 我希望这会有所帮助,因为您的问题是如何解析输入。
f = open('stream.txt', 'r')
global found_coordinate
found_coordinate = False
while True:
line = f.readline()
if not line:
break
if "SENSOR COORDINATE" in line:
found_coordinate = True
coordinate = int(line.split("=")[1].strip())
print("Coordinate",coordinate)
if "MEASURED RESISTANCE" in line and found_coordinate:
found_coordinate = False
resistance = float(line.split("=")[1].split("kOhm")[0].strip())
print("Resistance",resistance)
我希望这会有所帮助,如果我对您的要求的理解有任何差异,请告诉我,以便我修复我的代码。
注意:您实际上可能不需要.strip()
类型转换为int
或float
来处理这个问题,但是我仍然把它放在那里作为健全性检查
所以这里是你的readSerial
function:
def readSerial():
global after_id
while ser.in_waiting:
try:
ser_bytes = ser.readline()
print(ser_bytes)
ser_bytes = ser_bytes.decode("utf-8")
print(ser_bytes)
text.insert("end", ser_bytes)
if "SENSOR COORDINATE" in ser_bytes:
found_coordinate = True
coordinate = int(ser_bytes.split("=")[1].strip())
print("Coordinate",coordinate)
if "MEASURED RESISTANCE" in ser_bytes and found_coordinate:
found_coordinate = False
resistance = float(ser_bytes.split("=")[1].split("kOhm")[0].strip())
print("Resistance",resistance)
except UnicodeDecodeError:
print("UnicodeDecodeError")
else:
print("No data received")
after_id=root.after(50,readSerial)
如您所知,您已经在两个if
语句中定义了found_coordinate
。 但是让我们看看你在哪里引用found_coordinate
变量:
if "MEASURED RESISTANCE" in ser_bytes and found_coordinate:
那是您使用found_coordinate
变量的唯一地方,也是发生错误的地方。 现在考虑一下,如果
if "SENSOR COORDINATE" in ser_bytes:
never 评估为True
,则found_coordinate = True
线从未遇到,这意味着found_coordinate
从未被定义。 是的,您在另一行定义它,但它只能在以下条件下执行:
if "MEASURED RESISTANCE" in ser_bytes and found_coordinate:
同样, found_coordinate
变量尚未定义,导致错误。 您可能想知道:它是如何成功运行 10 秒而没有出现错误的? 这很简单:
在 10 秒内, if "SENSOR COORDINATE" in ser_bytes:
全部评估为False
,因此found_coordinate
变量从未被定义。 但同时 10 秒内"MEASURED RESISTANCE" in ser_bytes
也都评估为False
,所以程序没有继续到and found_coordinate
,因为没有必要。 错误发生时"MEASURED RESISTANCE" in ser_bytes
评估为True
,使程序解析and found_coordinate
,其中found_coordinate
尚未定义。
如果您可以更改 Arduino 代码,那么您可以利用 python 中的 json.load() 方法将字符串转换为更易于管理的内容。
我不喜欢 Arduinos(尽管有一个人坐着伸手可及,盒子未打开,在两年的大部分时间里......)所以下面的代码可能比实际代码更接近伪代码:
# This should (fingers crossed) build and send a separate message for each variable.
# It could relatively easily be combined into one message.
double resistanse = ((period * GAIN_VALUE * 1000) / (4 * CAPACITOR_VALUE)) - R_BIAS_VALUE;
##########################################################
# If you want to send a separate message for each variable
String sSensor = "{\"sensorcoord\":";
String sResistance = "{\"resistance\":";
String sEnd = "}"
String sensor_output = sSensor + sensor_coord + sEnd
Serial.println(sensor_output)
# output will be {"sensorcoord":1}
String resistance_output = sResistance + resistanse + sEnd
Serial.println(resistance_output)
# output will be {"resistance":3.7}
########################################################
# If you want to send one message holding both variables
String sSensor = "{\"sensorcoord\":";
String sResistance = ",\"resistance\":";
String sEnd = "}"
String combined_output = sSensor + sensor_coord + sResistance + resistance + sEnd
Serial.println(combined_output)
# output will be {"sensorcoord": 1,"resistance":3.7}
将字符串输入 Python 后,您可以使用 json.loads() 获取(格式正确)文本字符串并将其转换为 object,您可以更轻松地访问:
import json
data = json.loads(textstringFromArduino)
# If you sent each value separately, you now need to work out which value you are receiving.
for key, value in data.items():
if key == "sensorcoord":
print(value)
elif key == "resistance":
print(value)
# If you sent both values in one message, it's a lot easier...
print(data['sensorcoord'])
print(data['resistance'])
你的尝试几乎就在那里。 UnboundLocalError
发生是因为如果线是阻力线,则变量found_coordinate
未在 function 中定义。 您也应该将其定义为全局变量,因为您需要通过多个 function 调用来跟踪它。 我很感兴趣,第一组坐标/阻力有效。 也一样
global after_id, found_coordinate
在您的 function 的开头。
在您发布尝试之前,我写了这个答案。 该方法与您的方法非常相似。 使用你觉得有用的东西!
你根本不需要split()
。 由于您一次得到的只是一行,因此解析每一行并解释结果。 如果您找到了传感器坐标,请留意提供测量距离的直线。 一旦你拥有两者,记录它们并留意新的传感器坐标。
"SENSOR COORDINATE"
?
"MEASURED RESISTANCE"
?
首先,让我们定义一个 function 以仅从每行中提取数字:
import re
def get_numbers_from_line(line):
try:
numbers_rex = r"(\d+(?:\.\d+)*)"
matched_text = re.findall(numbers_rex, line)[0]
parsed_number = float(matched_text)
return parsed_number
except IndexError:
print(f"No numbers found on line {line}")
except ValueError:
print(f"Couldn't parse number {matched_text}")
# Only come here if error occurred. Not required, but for clarity we return None
return None
接下来,让我们定义一个 function 来解析每一行并决定如何处理它。 它将使用几个全局变量来跟踪其 state:
all_pairs = []
parsed_pair = []
def parse_line(line):
global all_pairs, parsed_pair
if "SENSOR COORDINATE" in line:
sensor_coord = get_numbers_from_line(line)
if parsed_pair:
# Something already exists in parsed_pair. Tell user we are discarding it
print("Data already existed in parsed_pair when a new SENSOR COORDINATE was received")
print("Existing data was discarded")
print(f"parsed_pair: {parsed_pair}")
if sensor_coord is not None:
# Make a new list containing only this newly parsed number
parsed_pair = [sensor_coord]
elif "MEASURED RESISTANCE" in line:
resistance = get_numbers_from_line(line)
if not parsed_pair:
# parsed_pair is empty, so no sensor coordinate was recorded.
# Ignore this line and wait for the start of the next pair of data
print("Received measured resistance without corresponding sensor coordinate")
print("Received data was discarded")
print(f"Received data: {resistance}")
elif resistance is not None:
parsed_pair.append(resistance) # Add resistance to the pair
all_pairs.append(parsed_pair) # Add the pair to all_pairs
parsed_pair = [] # Make a new empty list for the next pair
print(f"Added pair {parsed_pair}")
然后,在def readSerial():
text.insert("end", ser_bytes)
之后,调用这个 function。
def readSerial():
global after_id
while ser.in_waiting:
try:
ser_bytes = ser.readline() #read data from the serial line
ser_bytes = ser_bytes.decode("utf-8")
text.insert("end", ser_bytes)
parse_line(ser_bytes)
except UnicodeDecodeError:
print("UnicodeDecodeError")
else:
print("No data received")
after_id=root.after(50,readSerial)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.