Как мне преобразовать строку в хеш?

Я пытаюсь преобразовать строку в хеш.

str = "Notifications[0].Open=1
Notifications[0].Body.Message[0]=3455
Notifications[0].Body.Message[1]=2524
Notifications[0].Body.Message[2]=2544
Notifications[0].Body.Message[3]=2452
Notifications[0].Body.Error[0]=2455
Notifications[0].Body.Currency=EUR
Notifications[0].Published=true"

Результат должен выглядеть примерно так:

pairs = {
 'Open' = 1,
 'Published' => true
 'Body' => {
    'Message' => [3455, 2524, 2544, 2452],
    'Error' => [2455],
    'Currency' => 'EUR',
 }
}

Может быть, кто-нибудь поможет мне, как мне это сделать. На данный момент я могу думать только о регулярном выражении.

похоже, что этот вывод производит машина - можно ли его отформатировать по-другому?

Anthony 31.10.2018 15:02

Откуда изначально взялась струна?

Rogue 31.10.2018 18:56

Логика непонятна. Откуда взялся 'GBR'?

sawa 01.11.2018 10:25

@sawa это опечатка

fix12332 02.11.2018 12:29
1
4
72
2

Ответы 2

что-то вроде этого с регулярным выражением:

require 'pp'

str = "Notifications[0].Open=1
Notifications[0].Body.Message[0]=3455
Notifications[0].Body.Message[1]=2524
Notifications[0].Body.Message[2]=2544
Notifications[0].Body.Message[3]=2452
Notifications[0].Body.Error[0]=2455
Notifications[0].Body.Currency=EUR
Notifications[0].Published=true"

pairs         = {}
pairs['Body'] = {}
values        = []

str.scan(/Body\W+(.+)/).flatten.each do |line|
  key   = line[/\A\w+/]
  value = line[/\w+\z/]

  if line[/\A\w+\[\d+\]/] || key == 'Error'
    values = [] unless pairs['Body'][key]

    values << value
    value = values
  end

  pairs['Body'][key] = value
end

str.scan(/\[0\]\.(?!Body.).*/).each do |line|
  key   = line[/(?!\A)\.(\w+)/, 1]
  value = line[/\w+\z/]

  if line[/\A\w+\[\d+\]/]
    values = [] unless pairs[key]

    values << value
    value = values
  end

  pairs[key] = value
end

PP.pp pairs

-

{"Body"=>
  {"Message"=>["3455", "2524", "2544", "2452"],
   "Error"=>["2455"],
   "Currency"=>"EUR"},
 "Open"=>"1",
 "Published"=>"true"}

Вот. Этот код должен работать с любой структурой.

def parse(path, value, hash)
  key, rest = path.split('.', 2)
  if rest.nil?
    hash[key] = value
  else
    hash[key] ||= {}
    parse(rest, value, hash[key])
  end
end

def conv_to_array(hash)
  if hash.is_a?(Hash)
    hash.each do |key, value|
      hash[key] = if value.is_a?(Hash) && value.keys.all? { |k| k !~ /\D/ }
                    arr = []
                    value.each do |k, v|
                      arr[k.to_i] = conv_to_array(v)
                    end
                    arr
                  else
                    conv_to_array(value)
                  end
    end
    hash
  else
    if hash !~ /\D/
      hash.to_i
    elsif hash == 'true'
      true
    elsif hash == 'false'
      false
    else
      hash
    end
  end
end


str = "Notifications[0].Open=1
Notifications[0].Body.Message[0]=3455
Notifications[0].Body.Message[1]=2524
Notifications[0].Body.Message[2]=2544
Notifications[0].Body.Message[3]=2452
Notifications[0].Body.Error[0]=2455
Notifications[0].Body.Currency=EUR
Notifications[0].Published=true"

str = str.tr('[', '.').tr(']', '')
hash = {}
str.split(' ').each do |chunk|
  path, value = chunk.split('=')
  parse(path.strip, value.strip, hash)
end
hash = conv_to_array(hash)

hash['Notifications'][0]

# => {"Open"=>1, "Body"=>{"Message"=>[3455, 2524, 2544, 2452], "Error"=>[2455], "Currency"=>"EUR"}, "Published"=>true}

Другие вопросы по теме