4

我有这种格式的字符串

 2013-06-05T11:01:02.955 LASTNAME=Jone FIRSTNAME=Jason PERSONNELID=salalm QID=231412 READER_NAME="CAZ.1 LOBBY LEFT TURNSTYLE OUT" ACCESS_TYPE="Access Granted" EVENT_TIME_UTC=1370480141.000 REGION=UTAH

其中一些看起来像这样

 2013-06-05T11:15:48.670 LASTNAME=Ga FIRSTNAME="Je " PERSONNELID=jega QID=Q10138202 READER_NAME="CAZ.1 ELEVATOR LOBBY DBL GLASS" ACCESS_TYPE="Access Granted" EVENT_TIME_UTC=1370481333.000 REGION=UTAH

我想提取 PERSONNELID,REGION,ACCESS_TYPE,EVENT_TIME_UTC 的值

我打算使用 split(" ") 但是 READER_NAME 和 ACCESS_TYPE 值有一堆空格我可以转换为 JSON 并按键搜索吗

提取这些字符串的方法是什么。

先感谢您

4

3 回答 3

11

我过去发现有用的一种技巧是使用shlex.split

>>> s = '2013-06-05T11:01:02.955 LASTNAME=Jone FIRSTNAME=Jason PERSONNELID=salalm QID=231412 READER_NAME="CAZ.1 LOBBY LEFT TURNSTYLE OUT" ACCESS_TYPE="Access Granted" EVENT_TIME_UTC=1370480141.000 REGION=UTAH'
>>> split = shlex.split(s)
>>> split
['2013-06-05T11:01:02.955', 'LASTNAME=Jone', 'FIRSTNAME=Jason', 
'PERSONNELID=salalm', 'QID=231412', 'READER_NAME=CAZ.1 LOBBY LEFT TURNSTYLE OUT',
'ACCESS_TYPE=Access Granted', 'EVENT_TIME_UTC=1370480141.000', 'REGION=UTAH']

然后我们可以把它变成字典:

>>> parsed = dict(k.split("=", 1) for k in split if '=' in k)
>>> parsed
{'EVENT_TIME_UTC': '1370480141.000', 'FIRSTNAME': 'Jason', 
'LASTNAME': 'Jone', 'REGION': 'UTAH', 'ACCESS_TYPE': 'Access Granted', 
'PERSONNELID': 'salalm', 'QID': '231412', 
'READER_NAME': 'CAZ.1 LOBBY LEFT TURNSTYLE OUT'}

正如@abarnert 指出的那样,如果需要,您可以保留更多信息:

>>> dict(k.partition('=')[::2] for k in split)
{'2013-06-05T11:01:02.955': '', 'EVENT_TIME_UTC': '1370480141.000', 'FIRSTNAME': 'Jason', 'LASTNAME': 'Jone', 'REGION': 'UTAH', 'ACCESS_TYPE': 'Access Granted', 'PERSONNELID': 'salalm', 'QID': '231412', 'READER_NAME': 'CAZ.1 LOBBY LEFT TURNSTYLE OUT'}

等等。正如他所说的那样,关键点是您所展示的语法看起来很像最小的 shell 语法。OTOH,如果违反了您在其他地方展示的模式,您可能希望退回到编写自定义解析器。该shlex方法在应用时很方便,但并不像您想要的那样健壮。

于 2013-06-05T18:27:10.327 回答
3

让我们分析一下这个问题:您想匹配四个标识符中的一个,然后是一个=符号,然后是一个带引号的字符串或一系列非空白字符。

这是正则表达式的完美工作:

>>> s= ' 2013-06-05T11:01:02.955 LASTNAME=Jone FIRSTNAME=Jason PERSONNELID=salal
m QID=231412 READER_NAME="CAZ.1 LOBBY LEFT TURNSTYLE OUT" ACCESS_TYPE="Access Gr
anted" EVENT_TIME_UTC=1370480141.000 REGION=UTAH'
>>> import re
>>> regex = re.compile(r"""\b(PERSONNELID|REGION|ACCESS_TYPE|EVENT_TIME_UTC)
...                        =
...                        ("[^"]*"|\S+)""", re.VERBOSE)
>>> result = regex.findall(s)
>>> result
[('PERSONNELID', 'salalm'), ('ACCESS_TYPE', '"Access Granted"'), 
 ('EVENT_TIME_UTC', '1370480141.000'), ('REGION', 'UTAH')]
>>> dict(result)
{'EVENT_TIME_UTC': '1370480141.000', 'PERSONNELID': 'salalm', 
 'ACCESS_TYPE': '"Access Granted"', 'REGION': 'UTAH'}

解释:

\b确保匹配从单词边界开始。

"[^"]*"匹配一个引号,后跟任意数量的非引号字符和另一个引号。

\S+匹配一个或多个非空白字符。

通过将正则表达式的“有趣”部分括在括号中,构建捕获组,您可以分别获得匹配每个部分的元组列表。

于 2013-06-05T18:22:26.877 回答
3

寻找现有的解析器是个好主意。如果您能找到一种已经描述您的数据的格式,或者您可以轻松地将数据转换成这种格式,那么您就赢了。

在这种情况下,转换为 JSON 似乎与解析一样多。

但是您只是希望拆分为简单valuename=value组件,其中可以引用该value部分......这些规则与最小 shell 语法相同。所以,shlex会为你做的:

>>> import shlex
>>> shlex.split('2013-06-05T11:01:02.955 LASTNAME=Jone FIRSTNAME=Jason PERSONNELID=salalm QID=231412 READER_NAME="CAZ.1 LOBBY LEFT TURNSTYLE OUT" ACCESS_TYPE="Access Granted" EVENT_TIME_UTC=1370480141.000 REGION=UTAH')
['2013-06-05T11:01:02.955',
 'LASTNAME=Jone',
 'FIRSTNAME=Jason',
 'PERSONNELID=salalm',
 'QID=231412',
 'READER_NAME=CAZ.1 LOBBY LEFT TURNSTYLE OUT',
 'ACCESS_TYPE=Access Granted',
 'EVENT_TIME_UTC=1370480141.000',
 'REGION=UTAH']

您仍然需要将每一name=value对分成名称和值组件,但这只是namevalue.split('=', 1). 但是考虑到您有一些不是名称-值对 ( 2013-06-05T11:01:02.955) 的元素,您需要单独执行此操作几乎是隐含的。

当然,您始终可以选择将它们视为具有空值的名称-值对:

>>> dict(namevalue.partition('=')[::2] for namevalue in shlex.split(s))
{'2013-06-05T11:01:02.955': '',
 'ACCESS_TYPE': 'Access Granted',
 'EVENT_TIME_UTC': '1370480141.000',
 'FIRSTNAME': 'Jason',
 'LASTNAME': 'Jone',
 'PERSONNELID': 'salalm',
 'QID': '231412',
 'READER_NAME': 'CAZ.1 LOBBY LEFT TURNSTYLE OUT',
 'REGION': 'UTAH'}
于 2013-06-05T18:28:11.897 回答