将 ser.readline() 编码为 UTF-8

Encode ser.readline() as UTF-8

我有一个 Neo 6M GPS 模块,我正试图从中打印坐标。它目前正在以字节形式打印 NMEA 句子,\r\n 坚持到最后。这是一个例子:

b'$GPGGA,161812.371,4042.759,N,07400.317,W,1,12,1.0,0.0,M,0.0,M,,*7B\r\n'

要将字符串解析为坐标,我需要去掉 \r\nb' '

为此,我正在尝试 .strip("b'rn\\")。原来你只能剥离字符串,而不是字节。 为了克服字节和条带的不兼容,我尝试将字节解码为这样的字符串:(ser.readline().decode("utf-8")).strip("b'rn\")

这不是 运行 我得到了这个错误:

Traceback (most recent call last):
  File "gps2.py", line 10, in <module>
    newdata = (ser.readline().decode("utf-8")).strip("b'rn\")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfe in position 0: invalid start byte

下面是我的代码。有没有人能帮我解码和剥离它,或者以另一种方式摆脱 \r\nb' '

import serial
import time
import string
import pynmea2

while True:
    port = "/dev/ttyAMA0"
    ser = serial.Serial(port,baudrate=9600,timeout=0.5)
    dataout = pynmea2.NMEAStreamReader()
    newdata = (ser.readline().decode("utf-8")).strip("b'rn\")

    if newdata[0:6] == "$GPRMC":
        newmsg = pynmea2.parse(newdata)
        lat = newmsg.latitude
        lng = newmsg.longitude
        gps = ("Latitude = " + str(lat) + " and Longitude = " +str(lng))
        print(gps)
    elif newdata[0:6] == "$GPGLL":
        print("Found GPGLL record: " + newdata)
    else:
        print(newdata)

注意:我将原来的评论更改为答案,因为它比评论更长,以回应 OP 对原始问题的放大。

您无法摆脱 b' '。它不在数据中。这是一个 Python 约定,向您显示您的数据是字节串而不是常规字符串。调用 decode() 会将字节串转换为字符串。 \r\n,另一方面,在数据中是。它表明您的设备正在以 carriage-return/linefeed 对终止字符串。这两个都算作空白。开头的字符0xfe是一个字节序标记对\xfe\xff的第一部分,可以舍弃。所以你只需要 ser.readline()[2:].decode("utf-8").strip().

至于你在问题中没有提到的不可解释的数据,但在随后的评论中才提到:

无论是设备还是它的文档,我只能推测你正在为你想要的数据添加前缀的明显二进制数据。它肯定不是我能识别的任何类型的字符数据:它不是 UTF-8,也不是有效的 UTF-16,我的直觉是它也不是东亚 MBCS。而且它不太可能是浮点数或整数,因为没有单个零字节,二进制数字数据(和 UTF-32)往往有很多。

但是如果您想要的数据以 $GPGGA, 之类的已知常量开头,那么从您获得的数据流中挑选您想要的数据应该不会很困难。例如,假设你得到

b'i\x9a\xcab\x82\xbab\x8a\xb2b\x92\xc2b\x92\xca\x9ab\x8a\xa2R\xba\xc2jR":A\x1dMY\xb1\xcd\xb1\xc9\xb1\xc5\xc1\xb1\xc5\xe1\xb1\xd1\xd9\xb1\xc5\xd5\xdd\xb1\xc9\xc1\xb1\xc9\xd5\xb1\xc9\xd5\xb1\xc5\xc5\xd9\xb1\xc5\xd1\xb1\xc9\xd9\xb1\xd9\xc5\xb1\xc9\xe5\xc9\xb1\xc5\xd1\xb1\xc9\xdd\xb1\xc1\xc9\xb1\xc9\xd1\xdd\xb1\xc1\xd9\xa9\xdd\x195)\x91\x1dA\x1dMY\xb1\xcd\xb1\xcd\xb1\xc5\xc1\xb1\xc9\xe5\xb1\xd5\xd9\xb1\xc1\xd9\xcd\xb1\xc9\xd1\xb1\xcd\xc5\xb1\xd1\xe5\xb1\xc9\xc1\xe5\xb1\xc5\xd5\xa9\xdd\xcd5)\x91\x1dA\x1d11\xb1\xd5\xc5\xc9\xd5\xb9\xe5\xe5\xc1\xc5\xe1\xb19\xb1\xc1\xc1\xc1\xc9\xd5\xb9\xd5\xe1\xd1\xc1\xcd\xb1]\xb1\xc9\xc1\xc1\xdd\xcd\xd9\xb9\xc1\xc1\xb1\x05\xb1\x05\xa9\xdd\r5)\xff\xfe\xff$GPGGA,161812.371,4042.759,N,07400.317,W,1,12,1.0,0.0,M,0.0,M,,*7B\r\n'

(其中大部分是从您的 Pastebin 内容中复制的)并将其存储在 dataout 中。然后 dataout.partition(b'$GPGGA,')[-1].decode().strip() 会给你你期望的数字,无论 $GPGGA, 左边是否有不可解释的二进制数据。

站在你的角度,我仍然想知道二进制数据是什么。我认为这更有可能是由串行数据传输的复杂性引起的,而不是设备中的任何缺陷。我的猜测是它是真实数据,但可能带有意外数据位(pySerial 调用 bytesize)、停止位或奇偶校验。您对 serial.Serial() 的调用采用 8 个数据位的默认值,无奇偶校验,一个停止位。我不知道 serial 模块有多聪明,但可能是它在看到一些数据后可以从不正确的初始值中恢复过来。调制解调器可以在 25 年前通过查看(诚然,预先指定的)数据的前 2 个字节来做到这一点。