使用Python解析冒号分隔字符串为对象

3 投票
4 回答
6952 浏览
提问于 2025-04-16 16:24

我有一个字符串,它是一个REST API的返回值(http://requesttracker.wikia.com/wiki/REST),里面使用了冒号分隔的键值对。

id: 123414
name: Peter
message: bla bla
  bla bla

我该如何把这个字符串解析成一个对象呢?有没有现成的Python解析器可以使用?

这是我想要解析的字符串:

'RT/3.8.8 200 Ok\n\nid: ticket/46863\nQueue: customer-test\nOwner: Nobody\nCreator: young.park\nSubject: testing\nStatus: new\nPriority: 0\nInitialPriority: 0\nFinalPriority: 0\nRequestors: superuser@meme.com\nCc:\nAdminCc:\nCreated: Mon Apr 25 15:50:27 2011\nStarts: Not set\nStarted: Not set\nDue: Not set\nResolved: Not set\nTold: Not set\nLastUpdated: Mon Apr 25 15:50:28 2011\nTimeEstimated: 0\nTimeWorked: 0\nTimeLeft: 0\nCF.{Severity}: \n\n'

4 个回答

0

示例看起来像是定制的http消息(但其实不是;这样太简单了);你可以使用 rfc822.Message 来解析它们:

import rfc822
from cStringIO import StringIO

# skip status line; read headers
m = rfc822.Message(StringIO(raw_text[raw_text.index('\n\n')+2:]))

现在你可以访问每个单独的头信息:

>>> m.getheader('queue')
'customer-test'
>>> m.getrawheader('queue')
' customer-test\n'
>>> m.getheader('created')
'Mon Apr 25 15:50:27 2011'
>>> m.getdate('created')
(2011, 4, 25, 15, 50, 27, 0, 1, 0)

所有的头信息:

>>> from pprint import pprint
>>> pprint(dict(m.items()))
{'admincc': '',
 'cc': '',
 'cf.{severity}': '',
 'created': 'Mon Apr 25 15:50:27 2011',
 'creator': 'young.park',
 'due': 'Not set',
 'finalpriority': '0',
 'id': 'ticket/46863',
 'initialpriority': '0',
 'lastupdated': 'Mon Apr 25 15:50:28 2011',
 'owner': 'Nobody',
 'priority': '0',
 'queue': 'customer-test',
 'requestors': 'superuser@meme.com',
 'resolved': 'Not set',
 'started': 'Not set',
 'starts': 'Not set',
 'status': 'new',
 'subject': 'testing',
 'timeestimated': '0',
 'timeleft': '0',
 'timeworked': '0',
 'told': 'Not set'}
4

这看起来像是YAML格式的内容。你试过用PyYAML这个库吗?

>>> import yaml
>>> s = """id: 123414
... name: Peter
... message: bla bla
...   bla bla"""
>>> yaml.load(s)
{'message': 'bla bla bla bla', 'id': 123414, 'name': 'Peter'}
5

你需要明确说出是哪个REST API,并提供相关的文档链接。

乍一看,这似乎并不难:

# Look Ma, no imports!
>>> s = 'id: 1234\nname: Peter\nmessage: foo bar zot\nmsg2: tee:hee\n'
>>> dict(map(str.strip, line.split(':', 1)) for line in s.splitlines())
{'message': 'foo bar zot', 'msg2': 'tee:hee', 'id': '1234', 'name': 'Peter'}

但是:(1)文档应该指向一个解析器(2)任何事情都没有看起来那么简单,尤其是从一个简单的例子来看(见上面的tee:hee);如果你决定自己动手,应该把上面的单行代码拆分成多个步骤,这样你可以进行一些错误检查(比如,line.split()返回的结果必须正好是2个部分)。

更新:在提供API参考后:

乍一看,这个网站提供了大量的例子,但并没有明确说明格式是什么。我建议你仔细看看;如果还是不行,可以问问作者或维护者。

更新 2:在给出实际示例输入后,以及评论“我刚试过这个,结果崩溃了”之后:

提供的代码是针对第一个(模糊的)示例输入的,其中除了最后一行,所有行都包含冒号。还建议应该分开处理,而不是用一行代码来完成,并特别提到要检查split(':', 1)的结果。你用的是什么代码?“崩溃了”具体是什么意思?你有没有尝试自己找出问题并解决它?

你输入了什么数据?你期待的实际示例是用冒号分隔的键值对行,前面有一个标题行和一个空行,后面也有一个空行。这些可以通过对单行代码做一些简单的调整来轻松忽略掉:

>>> print dict(map(str.strip, line.split(':', 1)) for line in s.splitlines()[2:-1])
{'Status': 'new', 'Resolved': 'Not set', 'CF.{Severity}': '',
'TimeLeft': '0', 'Creator': 'young.park', 'Cc': '', 'Starts': 'Not set',
'Created': 'Mon Apr 25 15:50:27 2011', 'Due': 'Not set',
'LastUpdated': 'Mon Apr 25 15:50:28 2011', 'Started': 'Not set',
'Priority': '0', 'Requestors': 'superuser@meme.com',
'AdminCc': '', 'Owner': 'Nobody', 'Told': 'Not set',
'TimeEstimated': '0', 'InitialPriority': '0', 'FinalPriority': '0',
'TimeWorked': '0', 'Subject': 'testing'}
>>>

注意 1:上面的输出经过手动编辑,以避免横向滚动。

注意 2:包括了Created和LastUpdated条目(-:它们的值中包含冒号:-)

如果你不相信可以轻松忽略这些内容,你可以先进行行分割,并确认第一行包含预期的标题,第二行和最后一行是空的。

撰写回答