tags:

views:

1623

answers:

5

I would like to convert the following string into an array/nested array:

str = "[[this, is],[a, nested],[array]]"

newarray = # this is what I need help with!

newarray.inspect  # => [['this','is'],['a','nested'],['array']]
A: 

Looks like a basic parsing task. Generally the approach you are going to want to take is to create a recursive function with the following general algorithm

base case (input doesn't begin with '[') return the input
recursive case:
    split the input on ',' (you will need to find commas only at this level)
    for each sub string call this method again with the sub string
    return array containing the results from this recursive method

The only slighlty tricky part here is splitting the input on a single ','. You could write a separate function for this that would scan through the string and keep a count of the openbrackets - closedbrakets seen so far. Then only split on commas when the count is equal to zero.

Ben Childs
+1  A: 

Make a recursive function that takes the string and an integer offset, and "reads" out an array. That is, have it return an array or string (that it has read) and an integer offset pointing after the array. For example:

s = "[[this, is],[a, nested],[array]]"

yourFunc(s, 1) # returns ['this', 'is'] and 11.
yourFunc(s, 2) # returns 'this' and 6.

Then you can call it with another function that provides an offset of 0, and makes sure that the finishing offset is the length of the string.

+3  A: 

For a laugh:

 ary = eval("[[this, is],[a, nested],[array]]".gsub(/(\w+?)/, "'\\1'") )
 => [["this", "is"], ["a", "nested"], ["array"]]

Disclaimer: You definitely shouldn't do this as eval is a terrible idea, but it is fast and has the useful side effect of throwing an exception if your nested arrays aren't valid

Orion Edwards
+3  A: 

You'll get what you want with YAML.

But there is a little problem with your string. YAML expects that there's a space behind the comma. So we need this

str = "[[this, is], [a, nested], [array]]"

Code:

require 'yaml'
str = "[[this, is],[a, nested],[array]]"
### transform your string in a valid YAML-String
str.gsub!(/(\,)(\S)/, "\\1 \\2")
YAML::load(str)
# => [["this", "is"], ["a", "nested"], ["array"]]
wieczo
Thank you so much for this! I was about to go crazy trying to figure this out. :)
CalebHC
+1  A: 

You could also treat it as almost-JSON. If the strings really are only letters, like in your example, then this will work:

JSON.parse(yourarray.gsub(/([a-z]+)/,'"\1"'))

If they could have arbitrary characters (other than [ ] , ), you'd need a little more:

JSON.parse("[[this, is],[a, nested],[array]]".gsub(/, /,",").gsub(/([^\[\]\,]+)/,'"\1"'))
glenn mcdonald