我有这种格式的字符串
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并按键搜索
提取这些字符串的方法是什么。
提前谢谢
答案 0 :(得分: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
方法在适用时很方便,但不如您想要的那么强大。
答案 1 :(得分: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
确保匹配从word boundary开始。
"[^"]*"
匹配一个引号,后跟任意数量的非引号字符和另一个引号。
\S+
匹配一个或多个非空白字符。
通过将正则表达式的“有趣”部分括在括号中,构建capturing groups,您可以分别获得匹配的每个部分的元组列表。
答案 2 :(得分:3)
寻找现有的解析器是个好主意。如果您可以找到已经描述过您数据的格式,或者您可以轻松地将数据转换为您的数据,那么您就赢了。
在这种情况下,转换为JSON似乎与首先解析一样多。
但您只是希望拆分为简单的value
和name=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'}