Вопрос по arrays, ruby-on-rails, string, ruby – Как мне преобразовать эту строку Ruby в массив?

4

Как лучше всего превратить следующую строку Ruby в массив (я использую ruby 1.9.2 / Rails 3.0.11)

Консоль Rails:

>Item.first.ingredients
=> "[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\"]"
>Item.first.ingredients.class.name
=> "String"
>Item.first.ingredients.length
77

Желаемый вывод:

>Item.first.ingredients_a
["Bread, whole wheat, 100%, slice", "Egg Substitute", "new, Eggs, scrambled"]
>Item.first.ingredients_a.class.name
=> "Array
>Item.first.ingredients_a.length
=> 3

Если я сделаю это, например:

>Array(Choice.first.ingredients)

Я получаю это:

=> ["[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\", \"Oats, rolled, old fashioned\", \"Syrup, pancake\", \"Water, tap\", \"Oil, olive blend\", \"Spice, cinnamon, ground\", \"Seeds, sunflower, kernels, dried\", \"Flavor, vanilla extract\", \"Honey, strained/extracted\", \"Raisins, seedless\", \"Cranberries, dried, swtnd\", \"Spice, ginger, ground\", \"Flour, whole wheat\"]"] 

Я уверен, что должен быть какой-то очевидный способ решить эту проблему.

Для ясности, это будет редактируемым в поле textarea в форме, поэтому должно быть сделано как можно более безопасным.

Если вы не можете изменить метод ингредиентов, вы должны хотя бы опубликовать его, чтобы мы могли увидеть, что он выводит. Отмена этого, безусловно, возможна, но мы должны увидеть это, чтобы помочь. Mark Thomas
Лучший способ сделать это - изменитьingredients метод. Mark Thomas

Ваш Ответ

6   ответов
5
class Item
  def ingredients_a
    ingredients.gsub(/(\[\"|\"\])/, '').split('", "')
  end
end
strip off the extraneous characters split into array elements using the separating pattern
+1 это самыйdirect ответ на вопрос.elegant Ответ требует больше информации о том, как массив стал строкой.
Мне очень понравился ответ JSON.parse, но этот, вероятно, должен работать и, вероятно, является самым прямым решением проблемы. Nathan W
отрицательный голос без объяснения причин? :(
0

просто используйтеJSON.parse()

1

измените ваш метод ингредиентов, если вы действительно не хотите двух отдельных методов, которые возвращают строку и массив соответственно. Я предполагаю, что вы действительно хотите только вернуть массив. Ради аргумента, скажем, ваш метод ингредиентов в настоящее время возвращает переменную с именемingredients_string, Измените ваш метод так:

def ingredients
  ...
  ingredients_array = ingredients_string.split('"')
  ingredients_array.delete_if { |element| %(", "[", "]").include? element }
  ingredients_array
end
Для справки, я думаю, что предложение Эндрю Маршалла JSON.parse гораздо более элегантно.
0

что это вступит в игру, но что произойдет, если вы захотите использовать массив в качестве атрибута, вы можете рассмотреть сериализацию ..

class Item << ActiveWhatever
  serialize :ingredients, Array

  ...
end

Больше информации о сериализации здесьhttp://api.rubyonrails.org/classes/ActiveRecord/Base.html

Да, так что я полагаю, что я мог бы потенциально хранить данные в поле сериализуемого массива, но я все еще начинаю со строки, которая выглядит как в формате, указанном выше :) .. поэтому мне нужно преобразовать ее в массив, чтобы получить ее там :). Nathan W
1

ingredients метод возвращает.inspect вывод результирующего возвращаемого массива. Это не очень полезный вывод. У вас есть возможность изменить его, чтобы вернуть простой массив?

Что бы яnot сделать это использоватьeval, что только увеличит хакерство уже взломанного кода.

@andrew, я разрешаю редактирование массива через текстовую область в форме. Этот пример показывает, как информация поступает через параметры. Если есть другие, лучшие методы для поддержки массива, было бы здорово услышать. Nathan W
@NathanW Тогда я предполагаю этоis JSON отправляется? Если это не так, это должно быть.
@NathanW Я думаю, что проблема в том, почему ваш массив в строковой форме в первую очередь?
+1 Хотя это больше похоже на комментарий, он довольно близок к тому, что, вероятно, является правильным ответом с ограниченной информацией.
Я согласен с вами в том, что вы хотите избежать 'eval' apos; если возможно. Я мог бы потенциально переопределить метод или сделать другие вызовы, если это необходимо, но у меня все еще остается вопрос о том, каков наилучший способ преобразования строки в массив, поскольку тип данных может не измениться. Я мог бы потенциально хранить данные в сериализуемом текстовом поле и хранить там массив в некотором формате, который я предполагаю. Nathan W
8

JSON.parse "[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\"]"
#=> ["Bread, whole wheat, 100%, slice", "Egg Substitute", "new, Eggs, scrambled"]

это позволяет избежать многих ужасов использованияeval.

Хотя вы действительно должны подумать о том, почему вы в первую очередь храните свои данные таким образом, и подумайте об их изменении, чтобы вам не пришлось это делать. Кроме того, вероятно, что вы должны анализировать его в массивеingredients так что метод возвращает что-то более значимое. Если вы почти всегда выполняете одну и ту же операцию с возвращаемым значением метода, этот метод неверен.

@MarkThomas Полностью согласен, но информации оwhy данные представлены в формате строки, так что нужно (к сожалению) делать предположения.
Я бы сделал это, только если бы это был JSON. Только взгляд наingredients метод скажет.

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