customised random string generator in ruby - ruby

Below is my code to generate a random string by taking the number of length from the user . I want to enhance this by asking the user to enter number of numbers and special characters to be included and generate a string to match those requirements.
For example:
length: 7
number of numbers: 2
number of special chars: 1
Then my output should be something like:
ab2hg3!
Below is my code:
puts "enter the minimum length of the password"
lengths = gets.to_i
puts "enter the number of numbers to be included"
num = gets.to_i
def gen_pass(lengths)
chars = ('a'..'z').to_a + ('A'..'Z').to_a + (0..10).to_a
Array.new(lengths) {chars.sample}.join
end
puts gen_pass(lengths)
puts gen_pass(lengths)

Try this:
def gen_pass(lengths, number_of_numbers, number_of_special_chars)
chars = ('a'..'z').to_a + ('A'..'Z').to_a + (0..10).to_a
digits = (0..9).to_a
special_chars = "?<>',?[]}{=-)(*&^%$#`~{}".split('')
remaining_letters_count = lengths - number_of_numbers - number_of_special_chars
n = digits.sample(number_of_numbers)
s = special_chars.sample(number_of_special_chars)
c = chars.sample(remaining_letters_count)
str = n << s << c
str.flatten.shuffle.join
end
puts gen_pass(lengths, number_of_numbers, number_of_special_chars)

If this is an exercise you should do it yourself. If it's not, you are certainly doing it wrong.
Anyway, here is my try :
#!/usr/bin/env ruby
def secret(l,n,s)
random_string =
[*('A'..'Z'),*('a'..'z')].sample(l-n-s) +
[*('0'..'9')].sample(n) +
[*('!'..'/')].sample(s)
random_string.shuffle.join
end
p secret(5,2,1)
=> ".4F0r"

Related

Reading word into an array [ruby]

Trying to create a ceaser cipher in Ruby.
The problem I'm facing is that when the program reaches the while loop, it only performs the desired operation on the very last letter of the inputted word. Before I delve further into what I've tried, please find the code:
#!/usr/bin/ruby
#print 65.chr ASCII code for A
#print 97.chr ASCII code for a
a = 0
b = 97
d = []
e = 0
# Just to print the alphabet alongside the ASCII value
# (For sanity checking)
while a <= 25
print b.chr + " "
print b.to_s + "\n"
a = a + 1
b = b + 1
end
puts "\n Please enter a word to translate"
word = gets.strip
# The desired effect is to move the letter along by key value
puts "Please enter a key"
k = gets.chomp.to_i
# In its current state, what happens is only the last char
# is moved along by the key value.
while e <= word.length
word.each_byte do |c|
d[e] = c + k
end
e = e + 1
end
puts d
I'm thinking that the problem lies with the logic for the while loop. The way I am going to attack this is by reading the pre-converted word into an array, as opposed to using the .each_byte object.
I don't know how to do that and the guides/questions I've found don't quite answer the question. If anyone knows how to do this, or knows a better way of solving this- I'd be much appreciative.
you don't need the last while loop
word.each_byte do |c|
d[e] = c + k
e = e + 1
end
Something a bit more verbose:
alphabet = ('a'..'z').to_a
new_word = ''
puts "\n Please enter a word to translate"
word = gets.strip
puts "Please enter a key"
k = gets.chomp.to_i
word.split('').each_with_index do |letter, index|
alphabet_index = alphabet.index(letter)
new_index = alphabet_index + key
new_word[index] = alphabet[new_index]
end
puts "Your translated word is #{new_word}"
Caesar cipher is a simple shift cipher
word.each_byte do |c|
p c + k
end
Managed to get it working, thanks for all the help... Code for anyone interested:
#!/usr/bin/ruby
#print 65.chr A
#print 97.chr a
a = 0
b = 65
y = 97
d = []
e = 0
while a <= 25
print y.chr + " = " + y.to_s + " "
print b.chr + " = " + b.to_s + " " + "\n"
a = a + 1
b = b + 1
y = y + 1
end
puts "\n Please enter a word to translate"
word = gets.strip
puts "Please enter a key"
k = gets.chomp.to_i
word.each_byte do |c|
d[e] = c + k
e = e + 1
end
print "\n"
a = 0
arlen = d.count
while a != arlen
print d[a].chr
a = a + 1
end
print k

Compress a number as a string to fit in 256 char space

I'm trying to use a bitmask to provide as many binary values as possible so that the final value will store in the limited allocate memory for a string. My current methodology is to find a maximum number and convert it to a string base-36.
value = (0 | (1<<1318)).to_s(36)
The result is 255 chars of a compressed number from which I can extract my original number of 1318. The downside is I'm limited to 1,318 binary values and I want to expand that number. Are there any alternative strategies in Ruby to compress this number even further?
You can always encode your number into base s and then represent that as string with whatever alphabet you want.
def encode(n, alphabet)
s = alphabet.size
res = []
while (n > 0)
res << n % s
n = n / s
end
res.reverse.map { |i| alphabet[i] }.join
end
Your method is then equivalent to encode(n, alphabet), where alphabet is defined as
alphabet = ((0..9).to_a + ("a".."z").to_a).join
# => "0123456789abcdefghijklmnopqrstuvwxyz"
But you might as well use all possible characters instead of only 36 of them:
extended_alphabet = (0..255).map { |i| i.chr }.join
This gives a total of (256 ** 255) possibilities, i.e. up to (2 ** 2040), which is much better than your actual (2 ** 1318).
This encoding happens to be optimal because each character of your string can have at most 256 different values, and all of them are used here.
Decoding can then be performed as follows:
def decode(encoded, alphabet)
s = alphabet.size
n = 0
decode_dict = {}; i = -1
alphabet.each_char { |c| decode_dict[c] = (i += 1) }
encoded.each_char do |c|
n = n * s + decode_dict[c]
end
n
end
If you are going to use a fixed alphabet for all your encodings, I would suggest computing the decoding dictionnary outside of the function and taking it as a parameter instead of alphabet, to avoid computing it every time you try to encode a number.
Numbers are non-negative
If the numbers are non-negative we can encode each 8-bits of each number to a character that is part of a string, and then decode the string by converting each character to 8 bits of the number.
def encode(n)
str = ''
until n.zero?
str << (n & 255).chr
n = n >> 8
end
str.reverse
end
def decode(str)
str.each_char.reduce(0) { |n,c| (n << 8) | c.ord }
end
This uses the following bit-manipulation methods in the class Integer: &, >>, << and |.
def test(n)
encoded = encode(n)
puts "#{n} => #{encoded} => #{decode(encoded)}"
end
test 1 # 1 => ["\u0001"] => 1
test 63 # 63 => ["?"] => 63
test 64 # 64 => ["#"] => 64
test 255 # 255 => ["\xFF"] => 255
test 256 # 256 => ["\u0001", "\u0000"] => 256
test 123456 # 123456 => ["\x01", "\xE2", "#"] => 123456
For example,
n = 123456
n.to_s(2)
#=> "11110001001000000"
so
n = 0b11110001001000000
#=> 123456
The bytes of this number can be visualized so:
00000001 11100010 01000000
We see that
a = [0b00000001, 0b11100010, 0b01000000]
a.map(&:chr)
#=> ["\x01", "\xE2", "#"]
Numbers can be negative
If the numbers to be encoded can be negative we need to first convert then to their absolute values then add some information to the encoded string that indicates whether they are non-negative or negative. That will require at least one additional byte so we might include a "+" for non-negative numbers and a "-" for negative numbers.
def encode(n)
sign = "+"
if n < 0
sign = "-"
n = -n
end
str = ''
until n.zero?
str << (n & 255).chr
n = n >> 8
end
(str << sign).reverse
end
def decode(str)
n = str[1..-1].each_char.reduce(0) { |n,c| (n << 8) | c.ord }
str[0] == '+' ? n : -n
end
test -255 # -255 => ["-", "\xFF"] => -255
test -256 # -256 => ["-", "\u0001", "\u0000"] => -256
test -123456 # -123456 => ["-", "\x01", "\xE2", "#"] => -123456
test 123456 # 123456 => ["+", "\x01", "\xE2", "#"] => 123456

How to implement Caesar Cipher in Ruby?

I'm learning Ruby on theOdinProject and I need to build the Caeser Cipher. Here's my code:
def caesar_cipher plaintext, factor
codepoints_array = []
ciphertext = ""
plaintext.split('').each do |letter|
if letter =~ /[^a-zA-Z]/
codepoints_array << letter.bytes.join('').to_i
else
codepoints_array << letter.bytes.join('').to_i + factor
end
end
ciphertext = codepoints_array.pack 'C*'
puts ciphertext
end
caesar_cipher("What a string!", 5)
I bet it's not really "elegant" but the main issue here is that the output should be "Bmfy f xywnsl!" but what do I have is "\mfy f xywnsl!". I've been struggling with this task for a couple of days now, but I still have no idea how to "chain" the alphabet so 'z' becomes 'a' with the factor == 1.
I could check the finished tasks of the other people on theOdinProject but their code usually different/more professional and I tried to get a hint, not the final solution. I'll be really thankful if someone could hint me how to resolve this. Thank you in advance.
Hints
Your code would almost work fine if the ASCII table had only 26 characters.
But W is not w, and after z comes {, not a.
So you first need to apply downcase to your letters, offset the bytecode so that a is 0, and do every calculation modulo 26.
Modified version
def caesar_cipher plaintext, factor
codepoints_array = []
ciphertext = ""
a_codepoint = 'a'.ord
plaintext.split('').each do |letter|
if letter =~ /[^a-zA-Z]/
codepoints_array << letter.bytes.join('').to_i
else
shifted_codepoint = letter.downcase.bytes.join('').to_i + factor
codepoints_array << (shifted_codepoint - a_codepoint) % 26 + a_codepoint
end
end
ciphertext = codepoints_array.pack 'C*'
ciphertext
end
puts caesar_cipher("What a string!", 5) #=> "bmfy f xywnsl!"
Another solution
I wrote a small Ruby script for Vigenere chiper a while ago. Caesar cipher is just a variant of it, with the same factor for every character :
class Integer
# 0 => 'a', 1 => 'b', ..., 25 => 'z', 26 => 'a'
def to_letter
('a'.ord + self % 26).chr
end
end
class String
# 'A' => '0', 'a' => 0, ..., 'z' => 25
def to_code
self.downcase.ord - 'a'.ord
end
end
def caesar_cipher(string, factor)
short_string = string.delete('^A-Za-z')
short_string.each_char.map do |char|
(char.to_code + factor).to_letter
end.join
end
puts caesar_cipher("What a string!", 5) #=> "bmfyfxywnsl"
puts caesar_cipher("bmfyfxywnsl", -5) #=> "whatastring"
With ciphers, it is recommended to remove any punctuation sign or whitespace, because they make it much easier to decode the string with statistical analysis.
Caesar cipher is very weak anyway.

how to merge the hours minutes and seconds from a multiline string in ruby?

i am getting a multiline string in ruby. lets say
s = "00:01:07,11-234-090
00:05:01,22-080-080
00:05:00,11-234-090"
this string is separated by new line characters (\n). i want a method which sums up the duration (left side part of comma in every new line ex (00:01:07) based on the string(right side part after the comma in every line) means the first line and last line contains the same string after the comma (11-234-090). and in the second line the string after the comma is (22-080-080) as there is no same string in the entire string i want to keep this line as same.
input = "00:01:07,11-234-090
00:05:01,22-080-080
00:05:00,11-234-090"
output : "00:06:07,11-234-090
00:05:01,22-080-080"
here the 00 represent hour , 06 represents minutes and 07 represents seconds.
i want a method which returns the desired string by taking the input string
def returs_sumation_string(input_string)
return desired_string
end
i tried this:
s = "00:01:07,400-234-090
00:05:01,701-080-080
00:05:00,400-234-090"
splited = s.split("\n")
splited.map!{|s| s.strip}
this much i know. do not know how to proceed further.
Code
def aggregate(str)
str.strip.split(/\n\s*/).group_by { |s| s[-10..-1] }.map do |k,a|
secs = a.reduce(0) do |t,s|
h,m,s = s.split(":").map(&:to_i)
t + 3600*h + 60*m + s
end
h,secs = secs.divmod(3600)
m,secs = secs.divmod(60)
"%0#{h>99 ? 3:2 }d:%02d:%02d,%s" % [h,m,secs,k]
end
end
Example
str = "00:01:07,11-234-090
00:05:01,22-080-080
00:05:00,11-234-090"
aggregate(str)
#=> ["00:06:07,11-234-090", "00:05:01,22-080-080"]
Explanation
See the docs for methods Enumerable#group_by, Enumerable#reduce (aka inject) and Fixnum#divmod.
For str given in the example, the main steps are as follows.
b = str.strip
#=> "00:01:07,11-234-090\n 00:05:01,22-080-080\n 00:05:00,11-234-090"
c = b.split(/\n\s*/)
#=> ["00:01:07,11-234-090", "00:05:01,22-080-080", "00:05:00,11-234-090"]
d = c.group_by { |s| s[-10..-1] }
#=> {"11-234-090"=>["00:01:07,11-234-090", "00:05:00,11-234-090"],
# "22-080-080"=>["00:05:01,22-080-080"]}
d.map do |k,a|
secs = a.reduce(0) do |t,s|
h,m,s = s.split(":").map(&:to_i)
t + 3600*h + 60*m + s
end
h,secs = secs.divmod(3600)
m,secs = secs.divmod(60)
"%0#{h>99 ? 3:2 }d:%02d:%02d,%s" % [h,m,secs,k]
end
#=> ["00:06:07,11-234-090", "00:05:01,22-080-080"]
Now let's break down the last step. map passes the first element of c (an array containing a key-value pair) to the block, to which the block variables are assigned, using parallel assignment (sometimes called multiple assignment):
k, a = d.first
#=> ["11-234-090", ["00:01:07,11-234-090", "00:05:00,11-234-090"]]
k #=> "11-234-090"
a #=> ["00:01:07,11-234-090", "00:05:00,11-234-090"]
and the block calculation is performed. First we calculate the total number of seconds for the two elements of a. I've added some puts statements to show the calculations.
secs = a.reduce(0) do |t,s|
puts " t=#{t}, s=#{s}"
puts " h,m,s = #{s.split(":")}"
h,m,s = s.split(":").map(&:to_i)
puts " h=#{h}, m=#{m}, s=#{s}"
puts " t + 3600*h + 60*m + s=#{t + 3600*h + 60*m + s}"
t + 3600*h + 60*m + s
end
# t=0, s=00:01:07,11-234-090
# h,m,s = ["00", "01", "07,11-234-090"]
# h=0, m=1, s=7
# t + 3600*h + 60*m + s=67
# t=67, s=00:05:00,11-234-090
# h,m,s = ["00", "05", "00,11-234-090"]
# h=0, m=5, s=0
# t + 3600*h + 60*m + s=367
#=> 367
Continuing,
h,secs = secs.divmod(3600)
#=> [0, 367]
h
#=> 0
secs
#=> 367
m,secs = secs.divmod(60)
#=> [6, 7]
m
#=> 6
secs
#=> 7
"%0#{h>99 ? 3:2 }d:%02d:%02d,%s" % [h,m,secs,k]
#=> "00:06:07,11-234-090"
The final statement, the formatting of the string that is returned, uses format codes listed in the doc for Kernel::format. "%02d" means to format an integer 2 characters wide with zeroes used for any left padding required (e.g., "%02d" % [9] #=> "09"). "%0#{h>99 ? 3:2 }" means that the field width for hours should be 3 if there are more than 99 hours, else the width is 2.
Calculations for the second element of c are similar.
The group_by expression, group_by { |s| s[-10..-1] } means group the strings (produced by split) by the last 10 characters of the string. Alternatively, one could replace the first line with the following.
str.strip.split(/\n\s*/).group_by { |s| s.split(",").last }

Insert Something Every X Number of Characters Without Regex

In this question, the asker requests a solution that would insert a space every x number of characters. The answers both involve using a regular expression. How might you achieve this without a regex?
Here's what I came up with, but it's a bit of a mouthful. Any more concise solutions?
string = "12345678123456781234567812345678"
new_string = string.each_char.map.with_index {|c,i| if (i+1) % 8 == 0; "#{c} "; else c; end}.join.strip
=> "12345678 12345678 12345678 12345678"
class String
def in_groups_of(n)
chars.each_slice(n).map(&:join).join(' ')
end
end
'12345678123456781234567812345678'.in_groups_of(8)
# => '12345678 12345678 12345678 12345678'
class Array
# This method is from
# The Poignant Guide to Ruby:
def /(n)
r = []
each_with_index do |x, i|
r << [] if i % n == 0
r.last << x
end
r
end
end
s = '1234567890'
n = 3
join_str = ' '
(s.split('') / n).map {|x| x.join('') }.join(join_str)
#=> "123 456 789 0"
This is slightly shorter but requires two lines:
new_string = ""
s.split(//).each_slice(8) { |a| new_string += a.join + " " }

Resources