#python
#python
Вопрос:
у меня есть строка, которая является возвращаемым значением REST API (http://requesttracker.wikia.com/wiki/REST ) и использует пары ключ / значение, разделенные двоеточием.
id: 123414
name: Peter
message: bla bla
bla bla
Как я могу преобразовать эту строку в объект? существует ли существующий анализатор Python, который я могу использовать??
Вот строка, которую я хочу проанализировать:
'RT/3.8.8 200 Oknnid: ticket/46863nQueue: customer-testnOwner: NobodynCreator: young.parknSubject: testingnStatus: newnPriority: 0nInitialPriority: 0nFinalPriority: 0nRequestors: superuser@meme.comnCc:nAdminCc:nCreated: Mon Apr 25 15:50:27 2011nStarts: Not setnStarted: Not setnDue: Not setnResolved: Not setnTold: Not setnLastUpdated: Mon Apr 25 15:50:28 2011nTimeEstimated: 0nTimeWorked: 0nTimeLeft: 0nCF.{Severity}: nn'
Комментарии:
1. Пожалуйста, определите serialize . Я не думаю, что это означает то, что вы думаете, что это делает.
2. Вы имеете в виду, что ищете что-то для преобразования возвращенного формата данных в некоторый тип объекта?
3. ДА. Я имел в виду синтаксический анализ для некоторого типа объекта.
4. Пожалуйста, опубликуйте код, который вы пытались использовать для анализа этого объекта. Важно продемонстрировать свою работу и понимание.
5. То, что вы показали, неоднозначно. Пожалуйста, выполните
print repr(your_string))
и отредактируйте свой вопрос, чтобы точно отобразить результат — если вам нужно его сократить, отрежьте немного от середины; не отрубайте хвост.
Ответ №1:
Вам действительно нужно указать, какой REST api и предоставить ссылку на документацию.
На первый взгляд, это не выглядит слишком сложным:
# Look Ma, no imports!
>>> s = 'id: 1234nname: Peternmessage: foo bar zotnmsg2: tee:heen'
>>> 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)
. Какой код вы использовали? Что именно означает «произошел сбой»? Вы пытались сами разобраться, в чем была ваша проблема, и исправить ее?
Какими данными вы ее загрузили? Ваш долгожданный фактический образец содержит разделенные двоеточием строки key:value, которым предшествуют строка заголовка и пустая строка, за которой следует пустая строка. Они могут быть благополучно проигнорированы путем тривиальной корректировки однострочного:
>>> 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: Включает созданные и обновленные записи (-:, значения которых содержат двоеточия🙂
Если вы не верите в блаженное игнорирование вещей, вы можете сначала выполнить разделение строк и утверждать, что первая строка содержит что-то вроде ожидаемого заголовка, а вторая и последняя строки пусты.
Комментарии:
1. @WSM: Укажите такую информацию в своем ВОПРОСЕ (отредактируйте его!), а не в комментариях.
2. @John Machin Кстати, ваше решение выходит из строя из-за того, что кажется строкой, которую WSM хочет проанализировать, и это в моем ответе, со строкой без двоеточия
3. @WSM: «Укажите такую информацию в своем ВОПРОСЕ» ДААА! Он прав. Такая необычная идея, не так ли ??!
4. @eyquem: повторный сбой: (1) трудно представить, как вы можете вывести желания OP из текущего состояния его примера (2) смотрите последнее предложение моего ответа («проверка ошибок»)
5. @John Machin Что ж, если ему нужно ваше решение проверка ошибок, он приступает к первым шагам создания нового мини-анализатора. Кстати, извините меня, но иногда я не читаю с особым вниманием все комментарии
Ответ №2:
Это похоже на 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'}
Комментарии:
1. Когда я использую yaml.load(mystring), я получаю ScannerError: значения сопоставления здесь не разрешены в «<string>» …
Ответ №3:
Примеры выглядят как настроенные http-сообщения (но это не так; это было бы слишком просто); вы могли бы использовать rfc822.Message
для их разбора:
import rfc822
from cStringIO import StringIO
# skip status line; read headers
m = rfc822.Message(StringIO(raw_text[raw_text.index('nn') 2:]))
Теперь у вас есть доступ к отдельным заголовкам:
>>> m.getheader('queue')
'customer-test'
>>> m.getrawheader('queue')
' customer-testn'
>>> 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:
Учитывая ваш неудачный вопрос, мы вынуждены представить, в чем заключается ключевая проблема, потому что я не могу поверить, что вы никогда не слышали о методе string, поэтому я думаю, что вы понятия не имеете, как их использовать в этом случае.
Безусловно, есть способ получить то, что вы хотите, с помощью методов string, у меня есть идея об этом, но я предпочитаю обратиться непосредственно к инструменту регулярных выражений, думая, что сложность заключается в том, чтобы перехватить вторую часть после двоеточия, содержащую новые строки
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 blanbla bla'), ('the end', ' of the text')]
.
Редактировать
Таким образом, в этой «проблеме» не было никаких трудностей
import re
regx = re.compile ('^([^:n] ): *(.*?) *$',re.MULTILINE)
ch = ('RT/3.8.8 200 Okn' 'n'
'id: ticket/46863n' 'Queue: customer-testn'
'Owner: Nobo:dyn' 'Creator: young.parkn'
'Subject: testingn' 'Status: newn'
'Priority: 0n' 'InitialPriority: 0n'
'FinalPriority: 0n' 'Requestors: superuser@meme.comn'
'Cc:nAdminCc:n' 'Created: Mon Apr 25 15:50:27 2011n'
'Starts: Not setn' 'Started: Not setn'
'Due: Not setn' 'Resolved: Not setn'
'Told: Not setn' 'LastUpdated: Mon Apr 25 15:50:28 2011n'
'TimeEstimated: 0n' 'TimeWorked: 0n'
'TimeLeft: 0n' 'CF.{Severity}: n' 'n')
print dict(regx.findall(ch))
print
s = 'id: 1234nname: Peternmessage: foo bar zotnmsg2: tee:heen'
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'}
.
Джон Мачин, я не ошибся в этом новом регулярном выражении, мне потребовалась одна минута, чтобы переписать, и поначалу это не заняло бы намного больше времени, если бы нам не пришлось выпрашивать необходимую базовую информацию, необходимую для ответа
Три замечания:
-
если входные данные когда-либо изменятся и дополнительная пустая строка появится где-либо среди других, ваше решение завершится сбоем, в то время как мое решение с регулярными выражениями продолжит хорошо работать. Ваше решение должно быть завершено с
if ':' in line
-
Я сравнил время выполнения:
мое значение регулярного выражения 0,000152533352703 секунды, ваше 0,000225727012791 ( 48 %)
С if ':' in line
добавлением, это немного дольше: 0,000246958761519 секунд ( 62 %)
Скорость здесь не важна, но в других приложениях полезно знать, что регулярные выражения выполняются очень быстро (в 100 раз быстрее, чем lxml, и в 1000 раз быстрее, чем BeautifulSoup)
- вы специалист по формату CSV. Также возможно решение с использованием функций модуля StringIO и csv
Комментарии:
1. @eyquem: «ключ», содержащий пробел, например, «конец», вероятно, будет незаконным. Если это так, нам обоим нужно предложить выполнить некоторую проверку ошибок на следующем шаге.
2. @John Machin пробел перед первым двоеточием, вероятно, является незаконным; и, скорее всего, это не будет незаконным; и наличие другого двоеточия после первого, скорее всего, не является незаконным, но, возможно, скорее всего, будет незаконным; и мое предположение о том, что во второй части могут быть новые строки, скорее всего, неверно; и … и… Вы правы . Но я заранее дал себе отпущение грехов: «Учитывая ваш неудачный вопрос, мы вынуждены представить …» . Если мое решение неверно, я исправлю его, если спрашивающий когда-нибудь ответит
3. @eyquem: кроме того, (1) на самом деле вполне вероятно, что новая строка, встроенная в значение, либо запрещена, либо должна быть как-то заключена в кавычки / экранирована — и, вероятно, то же самое для двоеточия 🙂 (2) вы оставляете пробелы без пробелов для ключей и значений (3) было бы неплохо, если бы вы объяснили грамматику, которую вы предполагаете — регулярные выражения намного сложнее перепроектировать, чем разделительные строки / split / strip .
4. @eyquem: и вероятность того, что для опубликованного API не существует синтаксического анализатора, также довольно низка. Я просто перечисляю множество различных путей, которые может выбрать воображение 🙂
5. @John Machin 1) Да. Или нет. Кто знает? 2) Да, я решил не уставать от всех подобных потенциальных проблем. Иногда я хочу написать короткий ответ. 🙂 3) Он должен учиться, если хочет. В этом случае нетрудно понять шаблон