использование python для преобразования строки, разделенной двоеточием (:), в объект

#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) Он должен учиться, если хочет. В этом случае нетрудно понять шаблон