Parsing string to an array of strings in Ruby - arrays

I have a string in this format:
"dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
The last data doesn't have "\r\r\n".
I would like to parse it and change to it an array of strings:
["dataA", "dataB", "dataC", "dataD"]
I am wondering what is the best way to do this.

You could split your concatenated string by passing \r\r\n which is a common point between each value:
a = "dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
p a.split(/\r\r\n/)
# => ["dataA", "dataB", "dataC", "dataD"]

str = "dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
#=> "dataA\r\r\ndataB\r\r\ndataC\r\r\ndataD"
str.split
#=> ["dataA", "dataB", "dataC", "dataD"]
See the 4th paragraph of the doc for String#split. Ruby's definition of "whitespace" is given in the doc for String#strip. For
str = "a" + "b\t\t" + "c\n\n\n" + "d\v\v" + "e\f" + "f\r\r" + "g " + "h"
str.split
#=> ["ab", "c", "d", "e", "f", "g", "h"]
is therefore equivalent to
str.split(/[\t\n\v\f\r \0]+/)
#=> ["ab", "c", "d", "e", "f", "g", "h"]
Search for "Backslash Notation" here for definitions of these backslash characters: horizontal tab, line feed, vertical tab, form feed, carriage return, space.

Related

Swift Array - Difference between "Int.random(in: 0...25)" and "randomElement()"

I recently started learning swift via an online course.
I was given the Task to generate a passwort out of a given Array containing characters.
We learned mainly two code examples to randomly choose one.
variable[Int.random(in: 0...25)]
variable.randomElement()
Both work just fine when pulling out one single element out of an array but only "variable[Int.random(in: 0...25)" when combined multiple times with a plus (+).
Why is that?
I looked up the documentation but couldn't find an answer
https://developer.apple.com/documentation/swift/array/2994747-randomelement
Explanation:
This code works:
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
//The number of letters in alphabet equals 26
var password = alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)]
print(password)
This code does not work, because "randomElement()" gets grey after combining multiple with plus (why?)
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
//The number of letters in alphabet equals 26
var password = alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement()
print(password)
Edit:
Thanks for the fast explanation guys !
The difference is that randomElement returns an optional string ( String?), as opposed to the subscript that returns a non-optional. Why does randomElement return an optional string? Well, what if the array is empty?
And Swift can't figure out how to add 2 optional strings (let alone 6! So it just gives up). One way to fix this is to force-unwrap the return values of randomElement:
let password = alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()!
We know the array is not empty, so we can safely force-unwrap here.
Arguably, randomElement is the better method to use here, because it forces you to think about the situation where the array is empty, and handle it accordingly. The first approach with subscripts doesn't have checks for whether the array is empty, or whether the indices are correct, etc.
This is because of the different return type between the two approaches.
Indexing an array of strings return, as you would expect, the String at that index.
However the .randomElement() function has a different signature: it return an optional element of the sequence, in your case an optional string (String?).
The '+' operator is defined for strings, but not for optional Strings. To add together the elements returned from .randomElement() you would need to unwrap them first. Given you have a closed sequence you it would be safe to force unwrap them with '!':
var password = alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()!
Instead of writing many times the same code, try some loops:
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
var i = 0
var temp = ""
//The number of letters in alphabet equals 26
while i < 6 {
temp = temp + alphabet[Int.random(in: 0...25)]
i += 1
}
let password = temp
print(password)
beginner in swift with below solution
let passwordChrt:Array = [
"A", "a", "B", "b", "C" , "c", "D", "d", "E", "e", "F", "f", "G", "g", "H", "h",
"I", "i", "J", "j", "K", "k", "L", "l", "M", "m","N", "n", "O", "o", "P", "p",
"Q", "q", "R", "r", "S", "s", "T", "t", "U", "u", "V", "v", "W", "w","X", "x", "Y",
"y", "Z", "z", 1, 2, 3, 4, 5, 6, 7 , 8 ,9, 0, "!", "#", "#", "$", "%", "^", "&", "*"] as [Any]
var password:String = ""
passwordChrt.shuffled()
for _ in passwordChrt {
if password.count < 6 {
password.append("\(passwordChrt.randomElement() ?? <#default value#>)")
}
}
print(password)
Updated, newer version:
func randomPassword(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyz"
return String((0..<length).map { _ in letters.randomElement()! })
}
print(randomPassword(length: 6)) // e.g. output: "deckro"

How to Concatenate strings in Array using Ruby

I have following sveral arrays which each of them consists into a String.
x = ["t", "o", "d", "a", "y"]
y = ["i", "s"]
z = ["s", "u", "n", "d", "a", "y"]
my output should be like following:
x = [today]
y = [is]
Z = [sunday]
in together: today is sunday
How can i get expected array using ruby?
You will want to use the #join(separator) method.
See the official ruby docs for Array#join
Example:
['h', 'e', 'l', 'l', 'o'].join('')
=> "hello"
A good place to start learning the basics of Ruby is at Code Academy.
I also recommend dash for browsing documentation offline!
For final your output,
[x, y, z].map(&:join).join(' ')
You can use the .join() method like this:
x = ["t", "o", "d", "a", "y"]
y = ["i", "s"]
z = ["s", "u", "n", "d", "a", "y"]
x.join()
=> "today"
y.join()
=> "is"
z.join()
=> "sunday"
Then do this:
x.join + y.join + z.join()
=> "todayissunday"
Or combine x, y, z into one array and call join on it, like this:
Array(x + y + z).join
=> "todayissunday"

Im try to isolate the white space in ruby sentences

I am attempting to place all the characters of a string into its own index in an array and also am trying to replace " " (spaces) with 0's. The error I'm getting is that is says
?wrong number of arguments (given 0, expected 1)
but I'm not sure how to make include(' ') work.
Here is my code:
def findMe(words)
x = 0
convert = []
while x < words.length
if words[x].is_a? String && words[x].include? != " "
convert << words[x]
else
convert << 0
end
x = x + 1
end
p convert
end
findMe('Words and stuff.')
Desired Output: ["W", "o", "r", "d", "s", 0, "a", "n", "d", 0, "s", "t", "u", "f", "f", "."]
You're getting the "wrong number of arguments" error here:
words[x].include? != " "
You can quickly fix this by replacinng it with:
!words[x] == " "
A better way to do the whole thing would be:
words.gsub(" ", "0").chars
Use Array#chars.
'Words and stuff.'.chars.map { |c| c == " " ? "0" : c }
#=> ["W", "o", "r", "d", "s", "0", "a", "n", "d", "0", "s", "t", "u", "f", "f", "."]

How do I split an array into smaller arrays bsaed on a condition?

Ruby 2.4. I have an array of strings
2.4.0 :007 > arr = ["a", "b", "g", "e", "f", "i"]
=> ["a", "b", "g", "e", "f", "h", "i"]
How do I split my array into smaller arrays based on a condition? I have a function -- "contains_vowel," which returns true if a string contains "a", "e", "i", "o", or "u". How would I take an array of strings and split it into smaller arrays, using a divider function of "contains_vowel"? That is, for the above, the resulting array of smaller arrays would be
[["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
If an element of the larger array satisfies the condition, it would become an array of one element.
arr = ["a", "b", "g", "e", "f", "i"]
r = /[aeiou]/
arr.slice_when { |a,b| a.match?(r) ^ b.match?(r) }.to_a
=> [["a"], ["b", "g"], ["e"], ["f"], ["i"]]
String#match? made its debut in Ruby v2.4. For earlier versions you could use (for example) !!(b =~ r), where !! converts a truthy/falsy value to true/false. That converstion is needed because the XOR operator ^ serves double-duty: it's a logical XOR when a and b in a^b are true, false or nil, and a bit-wise XOR when the operands are integers, such as 2^6 #=> 4 (2.to_s(2) #=> "10"; 6.to_s(2) #=> "110"; 4.to_s(2) #=> "100").
One more way to skin a cat
def contains_vowel(v)
v.count("aeiou") > 0
end
def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
!contains_vowel(before) & !contains_vowel(after)
end.to_a
end
split_by_substring_with_vowels(arr)
#=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
What it does:
passes each consecutive 2 elements
splits when either of them contain vowels
Example with your other Array
arr = ["1)", "dwr", "lyn,", "18,", "bbe"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe"]]
Further example: (if you want vowel containing elements in succession to stay in the same group)
def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
v_before,v_after = contains_vowel(before),contains_vowel(after)
(!v_before & !v_after) ^ (v_before & v_after)
end.to_a
end
arr = ["1)", "dwr", "lyn,", "18,", "bbe", "re", "rr", "aa", "ee"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe", "re"], ["rr"], ["aa", "ee"]]
This checks if before and after are both not vowels Or if they both are vowels
I might use chunk which splits an array everytime the value of its block changes. Chunk returns a list of [block_value, [elements]] pairs, I used .map(&:last) to only get the sub-lists of elements.
arr = ["a", "b", "g", "e", "f", "h", "i"]
def vowel?(x); %w(a e i o u).include?(x); end
arr.chunk{|x| vowel?(x)}.map(&:last)
=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
contains_vowel = ->(str) { !(str.split('') & %w|a e i o u|).empty? }
_, result = ["a", "b", "g", "e", "f", "h", "i"].
each_with_object([false, []]) do |e, acc|
cv, acc[0] = acc[0], contains_vowel.(e)
cv ^ acc.first ? acc.last << [e] : (acc.last[-1] ||= []) << e
end
result
#⇒ [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
What we do here:
contains_vowel is a lambda to check whether the string contains a vowel or not.
we reduce the input array, collecting the last value (contained the previously handled string the vowel or not,) and the result.
cv ^ acc.first checks whether it was a flip-flop of vowel on the last step.
whether is was, we append a new array to the result
whether is was not, we append the string to the last array in the result.

Get array element values without square brackets and double quotes

I have a couple of Ruby arrays:
array1 = ["a", "b"]
array2 = ["a", "b", "c"]
array3 = ["a", "b", "c", "d"]
array4 = ["a", "b", "c", "d", "e"]
I need to return the following strings:
#array1
"a"
#array2
"a and b"
#array3
"a, b and c"
#array4
"a, b, c and d"
The last element of the array should never be displayed.
I don't know in advance how many elements an array contains or the value of these elements.
To achieve what I need, I came up with the following method:
def format_array(array)
if array.length - 1 == 1
array[0].to_s
elsif array.length - 1 == 2
array[0].to_s + " and " + array[1].to_s
elsif array.length - 1 > 2
array.sort.each_with_index do |key, index|
unless key == "e"
if index == array.length - 2
" and " + array[index].to_s
else
array[index].to_s + ", "
end
end
end
end
end
This method returns an arrays of values with square brackets and double quotes instead of lean strings. For instance, I get ["a", "b", "c", "d", "e"] instead of "a, b, c and d" for array4.
How can I make this work?
def join_with_commas_and_and(array)
if array.length <= 2
array.join(' and ')
else
[array[0..-2].join(', '), array[-1]].join(' and ')
end
end
EDIT: to ignore the last element, add this line as the first line in the function:
array = array[0..-2]
I think it's easiest to disregard 'and' until commas are inserted, then replace the last comma with 'and':
def fmt(arr)
return arr.first if arr.size == 2
str = arr[0..-2].join(', ')
str[str.rindex(',')] = ' and'
str
end
# ["a", "b"]: a
# ["a", "b", "c"]: a and b
# ["a", "b", "c", "d"]: a, b and c
# ["a", "b", "c", "d", "e"]: a, b, c and d

Resources