I have a string (e.g. "AABBCCDDEEFF") and want to split this into an array with each element containing two characters - ["AA", "BB", "CC", "DD", "EE", "FF"].
Try the String object's scan method:
>> foo = "AABBCCDDEEFF"
=> "AABBCCDDEEFF"
>> foo.scan(/../)
=> ["AA", "BB", "CC", "DD", "EE", "FF"]
Depending on your needs, this may work better:
> foo = "AAABBCDEEFF"
=> "AAABBCDEEFF"
> foo.scan(/.{1,2}/)
=> ["AA", "AB", "BC", "DE", "EF", "F"]
Not sure what your input looks like. The above answer will drop any characters that do not have a pair, this one will work on odd length strings.
Related
I wonder how could I split a binary string in Ruby.
I want to split the string where the previous character is different from the next one.
for example if i have the string
#s = "aaaabbabbaa"
I would like to create an array of strings
#array[0] = "aaaa"
#array[1] = "bb"
#array[2] = "a"
#array[3] = "bb"
#array[4] = "aa"
How could i do this?
Enumerable#chunk does that, but its defined on Enumerable - and String does not include Enumerable. Transform it into an Array of chars (and glue them back to strings) , like:
s = "aaaabbabbaa"
p array = s.chars.chunk(&:itself).map{|a| a.last.join} #=>["aaaa", "bb", "a", "bb", "aa"]
You could use a regular expression with scan:
#array = #s.scan(/((.)\2*)/).map(&:first)
#=> ["aaaa", "bb", "a", "bb", "aa"]
str = "aaaabbabbaa"
r = /
(?<=(.)) # match any character in capture group 1, in positive lookbehind
(?!\1) # do not match capture group 1, negative lookahead
/x # free-spacing regex definition mode
str.split(r)
#=> ["aaaa", "a", "bb", "b", "a", "a", "bb", "b", "aa", "a"]
By using two lookarounds no characters are lost when splitting on the regular expression.
using Enumerable#chunk_while
str = "aaaabbabbaa"
p str.chars.chunk_while(&:==).map(&:join)
Output : ["aaaa", "bb", "a", "bb", "aa"]
If I have a string such as "aabbbbccdddeffffgg" and I wanted to split the string into this array: ["aa", "bbbb", "cc", "ddd", "e", "ffff", "gg"], how would I go about that?
I know of string.split/.../ < or however many period you put there, but it doesn't account for if the strings are uneven. The point of the problem I'm working on is to take two strings and see if there are three characters in a row of one string and two in a row in the other. I tried
`letter_count_1 = {}
str1.each_char do |let|
letter_count_1[let] = str1.count(let)
end`
But that gives the count for the total amount of each character in the string, and some of the inputs are randomized with the same letter in multiple places, like, "aabbbacccdba"
So how do you split the string up by character?
You can use a regex with a back reference and the scan() method:
str = "aabbbbccdddeffffgg"
groups = []
str.scan(/((.)\2*)/) { |x| groups.push(x[0]) }
groups will look like this afterwards:
["aa", "bbbb", "cc", "ddd", "e", "ffff", "gg"]
Here is a non-regexp version
str = "aabbbbccdddeffffgg"
p str.chars.chunk(&:itself).map{|x|x.last.join} #=> ["aa", "bbbb", "cc", "ddd", "e", "ffff", "gg"]
/((\w)\2)/ finds repeating letters. I was hoping to avoid the two dimensional array that is produced by ignoring the letter matching second capture group like this: /((?:\w)\2)/. It seems that's not possible. Any ideas why?
Rubular example
You don't need any capture groups:
str = [*'a+'..'z+', *'A+'..'Z+', *'0+'..'9+', '_+'].join('|')
#=> "a+|b+| ... |z+|A+|B+| ... |Z+|0+|1+| ... |9+|_+"
"aaabbcddd".scan(/#{str}/)
#=> ["aaa", "bb", "c", "ddd"]
but if you insist on having one:
"aaabbcddd".scan(/(#{str})/).flatten(1)
#=> ["aaa", "bb", "c", "ddd"]
Is this cheating? You did ask if it was possible.
If you mean you're using String#scan, you can post-process the result to return only the first items Enumerable#map:
'helloo'.scan(/((\w)\2)/)
# => [["ll", "l"], ["oo", "o"]]
'helloo'.scan(/((\w)\2)/).map { |m| m[0] }
# => ["ll", "oo"]
I need to convert data from a string to an array. The string looks like this:
{a,b,c{1,2,3},d,e,f{11,22,33},g}
The array that I want to receive should look like this:
[a, b, c1, c2, c3, d, e, f11, f22, f33, g]
I tried to use the split method but it works poorly.
arr = str.split(' ');
keys = arr[0][2..-2]
keys = keys.split(',')
Do you have any ideas how it could be implemented?
Here's what I'd use:
string = '{a,b,c{1,2,3},d,e,f{11,22,33},g}'
array = string.scan(/[a-z](?:{.+?})?/).flat_map{ |s|
if s['{']
prefix = s[0]
values = s.scan(/\d+/)
([prefix] * values.size).zip(values).map(&:join)
else
s
end
}
array # => ["a", "b", "c1", "c2", "c3", "d", "e", "f11", "f22", "f33", "g"]
Here's how it works:
string.scan(/[a-z](?:{.+?})?/) # => ["a", "b", "c{1,2,3}", "d", "e", "f{11,22,33}", "g"]
returns the string broken into chunks, looking for a single letter followed by an optional string of { with some text then }.
values = s.scan(/\d+/) # => ["1", "2", "3"], ["11", "22", "33"]
As it's running in flat_map, if { is found, the numbers are scanned out.
([prefix] * values.size).zip(values).map(&:join) # => ["c1", "c2", "c3"], ["f11", "f22", "f33"]
And then an array of the prefix, with the same number of elements as there are values is created and zipped together, resulting in:
[["c", "1"], ["c", "2"], ["c", "3"]], [["f", "11"], ["f", "22"], ["f", "33"]]
The join glues those sub-arrays together. And flat_map flattens any subarrays created so the resulting output is a single array.
You need to arr = str.split(',') in the first step, because there is no whitespace between the values.
Also keep in mind you have {} to handle too.
This worked for me with simple regex and gsubing (though Tin Man's solution is better ruby):
def my_string_to_array(input_string)
groups = input_string.scan(/\w+\{.*?\}/)
groups.each do |group|
modified = group.gsub(',', ",#{group.match(/\w+/)[0]}").delete("{}")
input_string.gsub!(group, modified)
end
created_array = input_string.delete("{}").split(',')
end
string = '{a,b,c{1,2,3},d,e,f{11,22,33},g}'
my_string_to_array(string)
=> ["a", "b", "c1", "c2", "c3", "d", "e", "f11", "f22", "f33", "g"]
The way it works is that it first finds the groups having alphabets followed by braces and digits (like c{1,2,3})
For each such group, it modifies it by gsubing ',' with ',<alphabet>' and removing the braces.
Next, it replaces these groups with the modified ones in the original string.
And finally it removes the starting and ending braces in the original string, and converts it into an array.
I have the string "111221" and want to match all sets of consecutive equal integers: ["111", "22", "1"].
I know that there is a special regex thingy to do that but I can't remember and I'm terrible at Googling.
Using regex in Ruby 1.8.7+:
p s.scan(/((\d)\2*)/).map(&:first)
#=> ["111", "22", "1"]
This works because (\d) captures any digit, and then \2* captures zero-or-more of whatever that group (the second opening parenthesis) matched. The outer (…) is needed to capture the entire match as a result in scan. Finally, scan alone returns:
[["111", "1"], ["22", "2"], ["1", "1"]]
…so we need to run through and keep just the first item in each array. In Ruby 1.8.6+ (which doesn't have Symbol#to_proc for convenience):
p s.scan(/((\d)\2*)/).map{ |x| x.first }
#=> ["111", "22", "1"]
With no Regex, here's a fun one (matching any char) that works in Ruby 1.9.2:
p s.chars.chunk{|c|c}.map{ |n,a| a.join }
#=> ["111", "22", "1"]
Here's another version that should work even in Ruby 1.8.6:
p s.scan(/./).inject([]){|a,c| (a.last && a.last[0]==c[0] ? a.last : a)<<c; a }
# => ["111", "22", "1"]
"111221".gsub(/(.)(\1)*/).to_a
#=> ["111", "22", "1"]
This uses the form of String#gsub that does not have a block and therefore returns an enumerator. It appears gsub was bestowed with that option in v2.0.
I found that this works, it first matches each character in one group, and then it matches any of the same character after it. This results in an array of two element arrays, with the first element of each array being the initial match, and then the second element being any additional repeated characters that match the first character. These arrays are joined back together to get an array of repeated characters:
input = "WWBWWWWBBBWWWWWWWB3333!!!!"
repeated_chars = input.scan(/(.)(\1*)/)
# => [["W", "W"], ["B", ""], ["W", "WWW"], ["B", "BB"], ["W", "WWWWWW"], ["B", ""], ["3", "333"], ["!", "!!!"]]
repeated_chars.map(&:join)
# => ["WW", "B", "WWWW", "BBB", "WWWWWWW", "B", "3333", "!!!!"]
As an alternative I found that I could create a new Regexp object to match one or more occurrences of each unique characters in the input string as follows:
input = "WWBWWWWBBBWWWWWWWB3333!!!!"
regexp = Regexp.new("#{input.chars.uniq.join("+|")}+")
#=> regexp created for this example will look like: /W+|B+|3+|!+/
and then use that Regex object as an argument for scan to split out all the repeated characters, as follows:
input.scan(regexp)
# => ["WW", "B", "WWWW", "BBB", "WWWWWWW", "B", "3333", "!!!!"]
you can try is
string str ="111221";
string pattern =#"(\d)(\1)+";
Hope can help you