Reputation: 23
I have the string: "how to \"split string\" to \"following array\""
(how to "split string" to "following array").
I want to get the following array:
["how", "to", "split string", "to", "following array"]
I tried split(' ')
but the result is:
["how", "to", "\"split", "string\"", "to", "\"following", "array\""]
Upvotes: 0
Views: 1527
Reputation: 407
With x
as your string:
x.split(?").each_slice(2).flat_map{|n, q| a = n.split; (a << q if q) || a }
When you split on quotes, you know for certain that each string in the array goes: non-quoted, quoted, non-quoted, quoted, non-quoted etc...
If we group these into pairs then we get one of the following two scenarios:
[ "non-quoted", "quoted" ]
[ "non-quoted", nil ]
(only ever for the last pair of an unbalanced string)For example 1, we split nq and append q
For example 2, we split nq and discard q
i.e.: a = n.split; (a << q if q) || q
Then we join all the pairs back up (the flat part of flat_map
)
Upvotes: 0
Reputation: 36101
x.split('"').reject(&:empty?).flat_map do |y|
y.start_with?(' ') || y.end_with?(' ') ? y.split : y
end
Explanation:
split('"')
will partition the string in a way that non-quoted strings will have a leading or trailing space and the quoted ones wouldn't.flat_map
will further split an individual string by space only if it falls in the non-quoted category.Note that if there are two consecutive quoted strings, the space in between will be it's own string after the first space and will completely disappear after the second. Aka:
'foo "bar" "baz"'.split('"') # => ["foo ", "bar", " ", "baz"]
' '.split # => []
The reject(&:empty?)
is needed in case we start with a quoted string as
'"foo"'.split('"') # => ["", "foo"]
Upvotes: 3