2

我正在尝试解析从 python 中的 GSM 调制解调器收到的消息。

我有很多需要解析的消息。我每隔几个小时左右就会收到新消息。

这是我通过使用串行对象将数据从调制解调器读取到列表 x 后收到的数据示例。

AT+CMGL="ALL"


+CMGL: 1,"REC READ","+918884100421","","13/04/05,08:24:36+22"
here's message one 

+CMGL: 2,"REC READ","+918884100421","","13/04/05,09:40:38+22"
here's message two

+CMGL: 3,"REC READ","+918884100421","","13/04/05,09:41:04+22"
here's message three

+CMGL: 4,"REC READ","+918884100421","","13/04/05,10:04:18+22"
here's message four

+CMGL: 5,"REC READ","+918884100421","","13/04/05,10:04:32+22"
here's message five

.
.
.
.
.

还有很多消息,我在这里只列出了五个。

我的主要目的是提取消息的内容,例如我收到的每条消息的“这里是消息一”等等。

这是我现在正在使用的代码。

def reading():
     print "Reading all the messages stored on SIM card"
     phone.write(b'AT+CMGL="ALL"\r')
     sleeps()
     x=phone.read(10000)
     sleeps()
     print x
     print "Now parsing the message!"
     k="".join(x)
     parse(k)
     k=""
def parse(k):
    m = re.search("\+CMGL: (\d+),""(.+)"",""(.+)"",(.*),""(.+)""\r\n(.+)\r\n",k)
    print "6="
    print m.group(6)

电话是我用来从 GSM 调制解调器读取的串行对象。

这里 m.group(6) 是捕获第一条消息“here's message one”的消息内容

我怎样才能让它匹配所有消息的内容,而不仅仅是第一个。

我尝试设置多行标志,但没有奏效。也没有使用 re.findall() 代替 re.search()。

re.search 返回的匹配对象也是不可迭代的。

请帮忙。

4

3 回答 3

3

为此使用正则表达式不是一个非常强大的解决方案,因为它不会处理不同电话行为的变化。在您的示例中,响应的格式是

+CMGL: 1,"REC READ","+918884100421","","13/04/05,08:24:36+22"

但其他手机会给出类似的回复

+CMGL: 1,"REC READ","+31612123738",,"08/12/22,11:37:52+04"

注意第四个参数的区别,""而不是什么。检查27.005,文本模式下响应的语法是

+CMGL: <index>,<stat>,<oa/da>,[<alpha>],[<scts>][,<tooa/toda>,<length>]<CR><LF>
<data><CR><LF>

并且<alpha>确实是可选的。是的,可能会编写一个考虑到这一点的正则表达式,但是你会陷入两个问题 land


我建议您做的是切换到对响应进行正确解析,即:从第一个字符开始并根据预期的参数格式(和存在)分块推进。请参阅此答案以获取仅提取电话号码的快速而肮脏的方法。它不如我在下面描述的算法那么健壮(例如comma + 2假设太多)。

解析响应的绝对正确算法是:

匹配行首的前缀(例如+CMGL:)。然后开始解析区分以下标记:

  • 空白' ''\t'
  • 逗号','
  • 双引号'"'
  • 回车'\r'
  • 换行'\n'
  • 任何非空白非逗号非双引号非cr非lf字符

对于每个参数,首先忽略任何前导空格。如果得到逗号,则参数不存在,继续解析下一个参数。如果得到回车,下一个字符应该是换行符并到达行尾。如果得到一个非空白非...字符,这是一个数字参数的开始。收集此参数后面的所有非空白非...字符。在此之后,唯一的合法字符应该是零个或多个空格,后跟逗号或回车。如果让双引号字符前进到下一个双引号字符,那就是字符串的结尾(这是安全且正确的,因为即使字符串应该包含双引号字符,它们也会被转义但不是\")。在此之后,唯一的合法字符应该是零个或多个空格,后跟逗号或回车。

上面的内容一开始可能看起来有点不知所措,但当你开始处理它时,它真的没有那么复杂。

于 2013-04-06T10:41:07.800 回答
1

因为我没有得到你的材料,所以我只是做一个样品。

'\xef\xbb\xbfAT+CMGL="ALL"\n\n+CMGL: 1,"REC READ","+918884100421","","13/04/05,08:24:36+22"\nhere\'s message one \n\n+CMGL: 2,"REC READ","+918884100421","","13/04/05,09:40:38+22"\nhere\'s message two\n\n+CMGL: 3,"REC READ","+918884100421","","13/04/05,09:41:04+22"\nhere\'s message three\n\n+CMGL: 4,"REC READ","+918884100421","","13/04/05,10:04:18+22"\nhere\'s message four\n\n+CMGL: 5,"REC READ","+918884100421","","13/04/05,10:04:32+22"\nhere\'s message five\n'

这来自您使用''.join(). 然后我使用您的正则表达式模式,只需将 替换为\r\n因为\n我使用的示例使用\n. 我得到了结果。我不知道为什么findall不适合你。

def parse(x):
    res = []
    match = re.finditer("\+CMGL: (\d+),""(.+)"",""(.+)"",(.*),""(.+)""\n(.+)\n", x)
    for each in match:
        res.append(each.group(6))
    return res

我得到的结果是["here's message one ", "here's message two", "here's message three", "here's message four", "here's message five"]. finditer返回一个迭代器,findall也可以正常工作。

 def parse(x):
        res = []
        match = re.findall("\+CMGL: (\d+),""(.+)"",""(.+)"",(.*),""(.+)""\n(.+)\n", x)
        for each in match:
            res.append(each[5])
        return res
于 2013-04-06T10:02:33.053 回答
0

如果消息总是在换行符上

(?:[\n\r]+|^)\+CMGL.*?[\n\r]+(.*?)(?=[\n\r]+|$)

第 1 组包含您需要的消息

于 2013-04-06T08:51:27.737 回答