我有一个字符串,它是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'
答案 0 :(得分: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个。)
更新:
乍一看,该网站提供了大量的示例,但没有真正说明格式是什么。我建议你多给一眼;如果失败,请询问作者/维护者。
在给出实际的示例输入后,更新2 ,并在评论“我刚试了这个并且崩溃了”之后:
提供的代码是对第一个(模糊的)示例输入的响应,其中除了last之外的所有行都包含冒号。它伴随着一个建议,它应该分成几部分,而不是单行,特别是提到检查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条目( - :,其值包含冒号: - )
如果你不相信幸福地忽略了事情,你可以先做分裂线,并断言第一行包含类似预期标题的东西,并且第二行和最后一行是空的。
答案 1 :(得分: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'}
答案 2 :(得分:0)
鉴于你的问题很糟糕,我们开始想象什么是关键问题,因为我无法相信你从未听说过字符串的方法,所以我认为你不知道在这种情况下如何使用它们。
肯定有一种方法可以通过字符串的方法获得你想要的东西,我对此有了一个想法,但我更喜欢直接转向正则表达式工具,认为难以在冒号后面有第二部分。它
import re
regx = re.compile ('(^[^:]+):((?:[^:]+\r?\n)*[^:]+)$',re.MULTILINE)
coloned = '''id: 123414
name: Peter
message: bla bla
bla bla
the end: of the text'''
print regx.findall(coloned)
给出
[('id', ' 123414'), ('name', ' Peter'), ('message', ' bla bla\nbla bla'), ('the end', ' of the text')]
所以这个“问题”没有任何困难
import re
regx = re.compile ('^([^:\n]+): *(.*?) *$',re.MULTILINE)
ch = ('RT/3.8.8 200 Ok\n' '\n'
'id: ticket/46863\n' 'Queue: customer-test\n'
'Owner: Nobo:dy\n' 'Creator: young.park\n'
'Subject: testing\n' 'Status: new\n'
'Priority: 0\n' 'InitialPriority: 0\n'
'FinalPriority: 0\n' 'Requestors: superuser@meme.com\n'
'Cc:\nAdminCc:\n' 'Created: Mon Apr 25 15:50:27 2011\n'
'Starts: Not set\n' 'Started: Not set\n'
'Due: Not set\n' 'Resolved: Not set\n'
'Told: Not set\n' 'LastUpdated: Mon Apr 25 15:50:28 2011\n'
'TimeEstimated: 0\n' 'TimeWorked: 0\n'
'TimeLeft: 0\n' 'CF.{Severity}: \n' '\n')
print dict(regx.findall(ch))
print
s = 'id: 1234\nname: Peter\nmessage: foo bar zot\nmsg2: tee:hee\n'
print dict(regx.findall(s))
结果
{'Due': 'Not set', 'Priority': '0', 'id': 'ticket/46863', 'Told': 'Not set', 'Status': 'new', 'Started': 'Not set', 'Requestors': 'superuser@meme.com', 'FinalPriority': '0', 'Resolved': 'Not set', 'Created': 'Mon Apr 25 15:50:27 2011', 'AdminCc': '', 'Starts': 'Not set', 'Queue': 'customer-test', 'TimeWorked': '0', 'TimeLeft': '0', 'Creator': 'young.park', 'Cc': '', 'LastUpdated': 'Mon Apr 25 15:50:28 2011', 'CF.{Severity}': '', 'Owner': 'Nobo:dy', 'TimeEstimated': '0', 'InitialPriority': '0', 'Subject': 'testing'}
{'message': 'foo bar zot', 'msg2': 'tee:hee', 'id': '1234', 'name': 'Peter'}
John Machin,我没有弄清楚这个新的正则表达式,我花了一分钟重写,如果我们不必乞求必要的基本信息,一开始就不会花费更多的时间需要回答
三条评论:
如果输入发生变化并且其他地方出现补充空行,则解决方案将崩溃,而我的正则表达式解决方案将继续正常运行。您的解决方案需要使用if ':' in line
我比较了执行时间:
我的正则表达式 0.000152533352703 秒,您的 0.000225727012791 (+ 48%)
添加if ':' in line
后,会略长:0.000246958761519秒(+ 62%)
速度在这里并不重要,但在其他应用程序中,最好知道正则表达式非常快(比lxml快100倍,比BeautifulSoup快1000倍)
答案 3 :(得分:0)
Examples看起来像是自定义的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'}