2012-05-10 5 views
4

Что такое лучший способ превратить следующий Рубиновый строку в массив (я использую рубин 1.9.2/Rails 3.0.11)Как преобразовать эту строку Ruby в массив?

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 в форме, поэтому должно быть сделано как можно безопаснее.

+1

Лучший способ сделать это состоит в изменении 'ingredients' метода. –

+1

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

ответ

5
class Item 
    def ingredients_a 
    ingredients.gsub(/(\[\"|\"\])/, '').split('", "') 
    end 
end 
  1. полосы от посторонних символов
  2. разбит на элементы массива, используя шаблон разделительной
+0

Мне очень понравился ответ JSON.parse, но этот, вероятно, должен работать и, вероятно, является самым прямым решением проблемы. –

+2

+1 Это самый * прямой * ответ на вопрос. * Элегантный * ответ требует больше информации о том, как массив стал строкой в ​​первую очередь. –

+0

нисходящий поток без объяснения причин? :( –

1

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

Что я хотел бы не do is eval, что только увеличит взлома уже взломанного кода.

+0

Я согласен с вами в желании избежать «eval», если это возможно. Я мог бы потенциально переопределить метод или сделать другие вызовы, если это необходимо, но у меня все еще вопрос о том, как лучше всего преобразовать строку в массив, потому что тип данных может не измениться. Я мог бы хранить данные в сериализуемом текстовом поле и хранить массив там в некотором формате, я думаю. –

+0

@NathanW Я думаю, проблема в том, почему именно ваш массив в строковой форме в первую очередь? –

+0

+1 Хотя это больше похоже на комментарий, оно довольно близко к тому, что, вероятно, является правильным ответом с ограниченной информацией. –

0

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

class Item << ActiveWhatever 
    serialize :ingredients, Array 

    ... 
end 

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

+0

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

1

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

def ingredients 
    ... 
    ingredients_array = ingredients_string.split('"') 
    ingredients_array.delete_if { |element| %(", "[", "]").include? element } 
    ingredients_array 
end 
+1

Для записи я думаю, что предложение JSON.parse от Andrew Marshall намного более изящно. –

8

Что у вас есть внешний вид, как JSON, так что вы можете сделать:

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

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

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

+0

Я бы сделал это, только если бы это был JSON. Посмотрите только на метод 'components'. –

+0

@MarkThomas Полностью согласен, но информации о * почему * не так много, поэтому данные находятся в строчном формате, который есть, поэтому один (к сожалению) должен сделать предположения. –

0

Если строка-массив является стандартным форматом JSON, просто использовать JSON.parse()

Смежные вопросы