Простой способ преобразовать строку в словарь

Я не могу действительно выручить Вас с реализацией Java. Microsoft, конечно, имейте их собственный адаптер Biztalk для ISO15022 и 20022. И они на самом деле сделают проверку довольно хорошо. Но поскольку Вы говорите фактический поиск решения для Java.

Вы могли бы найти, как я сделал, когда я исследовал это 6 лет назад, тот FIN отображения сообщения к XML и затем к в объекты, стандартная библиотека только получит Вас частично к Вашей цели. Необходимо будет интегрировать это с приложением бэкенда и безотносительно методов рынка, с которыми Вы сталкиваетесь в конкретных сообщениях, которые необходимо поддерживать.

я наконец закончил тем, что писал универсальный синтаксический анализатор FIN/150022 библиотека классов в C++.

Так или иначе, удача. Идея состоит в том, чтобы быть более конкретной в Вашем вопросе. Какие типы сообщений необходимо поддерживать?

6
задан astrofrog 29 November 2009 в 02:03
поделиться

9 ответов

У меня работает:

# get all the items
matches = re.findall(r'\w+=".+?"', s) + re.findall(r'\w+=[\d.]+',s)

# partition each match at '='
matches = [m.group().split('=', 1) for m in matches]

# use results to make a dict
d = dict(matches)
9
ответ дан 8 December 2019 в 13:46
поделиться

Вот более подробный подход к проблеме с использованием pyparsing. Обратите внимание на действия синтаксического анализа которые выполняют автоматическое преобразование типов из строк в целые числа или числа с плавающей запятой. Так же Класс QuotedString неявно удаляет кавычки из цитируемого значения. В заключение, класс Dict принимает каждую группу 'key = val' в списке, разделенном запятыми, и назначает имена результатов с использованием токенов ключа и значения.

from pyparsing import *

key = Word(alphas)
EQ = Suppress('=')
real = Regex(r'[+-]?\d+\.\d+').setParseAction(lambda t:float(t[0]))
integer = Regex(r'[+-]?\d+').setParseAction(lambda t:int(t[0]))
qs = QuotedString('"')
value = real | integer | qs

dictstring = Dict(delimitedList(Group(key + EQ + value)))

Теперь проанализируем исходную текстовую строку и сохраним результаты в dd. Pyparsing возвращает объект типа ParseResults, но этот класс имеет много функций, подобных dict (поддержка keys (), items (), in и т. д.) или может выдать настоящий Python dict, вызвав asDict (). Вызов дампа () показывает все токены в исходном проанализированном списке, а также все названные элементы. Последний два примера показывают, как получить доступ к именованным элементам в ParseResults, как если бы они были атрибутами объект Python.

text = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
dd = dictstring.parseString(text)
print dd.keys()
print dd.items()
print dd.dump()
print dd.asDict()
print dd.name
print dd.avatar

Печать:

['age', 'location', 'name', 'avatar', 'height']
[('age', 34), ('location', 'US'), ('name', 'John Smith'), ('avatar', ':,=)'), ('height', 173.19999999999999)]
[['name', 'John Smith'], ['age', 34], ['height', 173.19999999999999], ['location', 'US'], ['avatar', ':,=)']]
- age: 34
- avatar: :,=)
- height: 173.2
- location: US
- name: John Smith
{'age': 34, 'height': 173.19999999999999, 'location': 'US', 'avatar': ':,=)', 'name': 'John Smith'}
John Smith
:,=)
2
ответ дан 8 December 2019 в 13:46
поделиться

Следующий код дает правильное поведение, но немного длиннее! Я добавил пробел в аватар, чтобы показать, что он хорошо справляется с запятыми, пробелами и знаками равенства внутри строки. Есть предложения по сокращению?

import hashlib

string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'

strings = {}

def simplify(value):
    try:
        return int(value)
    except:
        return float(value)

while True:
    try:
        p1 = string.index('"')
        p2 = string.index('"',p1+1)
        substring = string[p1+1:p2]
        key = hashlib.md5(substring).hexdigest()
        strings[key] = substring
        string = string[:p1] + key + string[p2+1:]
    except:
        break

d = {}    
for pair in string.split(', '):
    key, value = pair.split('=')
    if value in strings:
        d[key] = strings[value]
    else:
        d[key] = simplify(value)

print d    
1
ответ дан 8 December 2019 в 13:46
поделиться

Редактировать : поскольку модуль csv не работает должным образом с кавычками ] внутри полей , для реализации этой функции требуется немного больше работы:

import re
quoted = re.compile(r'"[^"]*"')

class QuoteSaver(object):

  def __init__(self):
    self.saver = dict()
    self.reverser = dict()

  def preserve(self, mo):
    s = mo.group()
    if s not in self.saver:
      self.saver[s] = '"%d"' % len(self.saver)
      self.reverser[self.saver[s]] = s
    return self.saver[s]

  def expand(self, mo):
    return self.reverser[mo.group()]

x = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'

qs = QuoteSaver()
y = quoted.sub(qs.preserve, x)
kvs_strings = y.split(',')
kvs_pairs = [kv.split('=') for kv in kvs_strings]
kvs_restored = [(k, quoted.sub(qs.expand, v)) for k, v in kvs_pairs]

def converter(v):
  if v.startswith('"'): return v.strip('"')
  try: return int(v)
  except ValueError: return float(v)

thedict = dict((k.strip(), converter(v)) for k, v in kvs_restored)
for k in thedict:
  print "%-8s %s" % (k, thedict[k])
print thedict

Я дважды испускаю thedict , чтобы точно показать, как и почему он отличается от требуемого результата; вывод следующий:

age      34
location US
name     John Smith
avatar   :,=)
height   173.2
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)',
 'height': 173.19999999999999}

Как вы видите, вывод для значения с плавающей запятой соответствует запросу при непосредственном запуске с print , но это не так, и не может быть (поскольку там IS нет значения с плавающей запятой, которое отображало бы 173,2 в таком случае! -), когда print применяется ко всему dict (потому что это неизбежно использует repr для ключей и значений - и repr ] of 173.2 имеет такую ​​форму, учитывая обычные проблемы с тем, как значения с плавающей запятой хранятся в двоичном, а не в десятичном формате и т. д. и т. д.). Вы можете определить подкласс dict , который заменяет __ str __ значениями с плавающей запятой специального регистра, если это действительно требуется.

Но я надеюсь, что это отвлечение не помешает с основной идеей - пока двойные кавычки правильно сбалансированы (и нет двойных кавычек-внутри-двойных кавычек), этот код действительно выполняет требуемую задачу по сохранению «специальных символов» (запятых и знаков равенства, в данном случае) взяты в их обычном смысле, когда они заключены в двойные кавычки, даже если двойные кавычки начинаются внутри «поля», а не в начале поля ( csv касается только последнего условия). Вставьте несколько промежуточных отпечатков, если способ работы кода неочевиден - сначала он изменяет все «поля с двойными кавычками» в особенно простую форму ( «0» , «1» и так далее), при этом отдельно записывая фактическое содержание, соответствующее этим простым формам; в конце простые формы возвращаются к исходному содержанию. Удаление двойных кавычек (для строк) и преобразование не заключенных в кавычки строк в целые числа или числа с плавающей запятой в конечном итоге обрабатываются простой функцией конвертер .

4
ответ дан 8 December 2019 в 13:46
поделиться

Вот подход с eval , хотя я считал его ненадежным , но он работает для вашего примера.

>>> import re
>>>
>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>>
>>> eval("{"+re.sub('(\w+)=("[^"]+"|[\d.]+)','"\\1":\\2',s)+"}")
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
>>>

Обновление:

Лучше используйте тот, который указал Крис Лутц в комментарии, я считаю его более надежным, потому что даже в значениях dict есть (одинарные / двойные) кавычки, это может работает.

1
ответ дан 8 December 2019 в 13:46
поделиться

сделать это шаг за шагом

d={}
mystring='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"';
s = mystring.split(", ")
for item in s:
    i=item.split("=",1)
    d[i[0]]=i[-1]
print d
0
ответ дан 8 December 2019 в 13:46
поделиться

Я думаю, вам просто нужно установить maxsplit = 1, например, должно работать следующее.

string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'
newDict = dict(map( lambda(z): z.split("=",1), string.split(", ") ))

Изменить (см. Комментарий):

Я не заметил, что "," было значение под аватаром, лучше всего было бы избежать "," где бы вы ни генерировали данные. Еще лучше было бы что-то вроде JSON;). Однако в качестве альтернативы регулярному выражению вы можете попробовать использовать shlex, который, как мне кажется, дает более чистый код.

import shlex

string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'
lex = shlex.shlex ( string ) 
lex.whitespace += "," # Default whitespace doesn't include commas
lex.wordchars += "."  # Word char should include . to catch decimal 
words = [ x for x in iter( lex.get_token, '' ) ]
newDict = dict ( zip( words[0::3], words[2::3]) )
0
ответ дан 8 December 2019 в 13:46
поделиться

Всегда разделять запятыми? Используйте модуль CSV для разделения строки на части (не отмечен):

import csv
import cStringIO

parts=csv.reader(cStringIO.StringIO(<string to parse>)).next()
-2
ответ дан 8 December 2019 в 13:46
поделиться

Вот несколько более надежная версия решения regexp:

import re

keyval_re = re.compile(r'''
   \s*                                  # Leading whitespace is ok.
   (?P<key>\w+)\s*=\s*(                 # Search for a key followed by..
       (?P<str>"[^"]*"|\'[^\']*\')|     #   a quoted string; or
       (?P<float>\d+\.\d+)|             #   a float; or
       (?P<int>\d+)                     #   an int.
   )\s*,?\s*                            # Handle comma & trailing whitespace.
   |(?P<garbage>.+)                     # Complain if we get anything else!
   ''', re.VERBOSE)

def handle_keyval(match):
    if match.group('garbage'):
        raise ValueError("Parse error: unable to parse: %r" %
                         match.group('garbage'))
    key = match.group('key')
    if match.group('str') is not None:
        return (key, match.group('str')[1:-1]) # strip quotes
    elif match.group('float') is not None:
        return (key, float(match.group('float')))
    elif match.group('int') is not None:
        return (key, int(match.group('int')))

Оно автоматически преобразует числа с плавающей запятой и целые числа в правильный тип; обрабатывает одинарные и двойные кавычки; обрабатывает посторонние пробелы в разных местах; и жалуется, если предоставлена ​​неверно отформатированная строка

>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>> print dict(handle_keyval(m) for m in keyval_re.finditer(s))
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
1
ответ дан 8 December 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: