Change users input but store original input separately - arrays

My assignment is to take the user's input and change every 'c' and 's' to 's' and 'th'.
After that it asked me to store the original user's input so it would not get changed.
I can't figure it out in Ruby.
print "What can we do for you?"
user_input = gets.chomp
user_input.downcase!
if user_input.length == 0
puts "Well you will have to write something...!"
elsif user_input.include?("s") || user_input.include?("c")
puts "We got ourselves some 's's and some 'c's"
user_input.gsub!(/s/, "th")
user_input.gsub!(/c/, "s")
puts "The changed version: '#{user_input}!'"
else
print "Nope, no 's' or 'c' found"
end

Don’t use inplace version of gsub:
# user_input.gsub!(/s/, "th")
# user_input.gsub!(/c/, "s")
gsubbed = user_input.gsub(/s/, "th").gsub(/c/, "s")
puts "Changed version: '#{gsubbed}'"
puts "Original version: '#{user_input}'"
Note the lack of exclamation signs in functions names.

Related

Best methods to extract substring into arguments and allow arguments with multiple "main split character" indicated by a character in Lua?

Let's say I have this string
"argument \"some argument\""
which prints out as
argument "some argument"
And now as example, let's say I would want to split it using the "space character" as the "main split character" to split, but allow me to indicate with a character which part to have multiple arguments of. So let's say it would be the quotation mark ". At the it should extract the arguments like so
> [1] = "argument"
> [2] = "some argument"
I am able to do this with the code here:
ExtractArgs = function(text,splitKey)
local skip = 0
local arguments = {}
local curString = ""
for i = 1, text:len() do
if (i <= skip) then continue end
local c = text:sub(i, i)
if (c == "\"") and (text:sub(i-1, i-1) ~= "\\") then
local match = text:sub(i):match("%b\"\"")
if (match) then
curString = ""
skip = i + match:len()
arguments[#arguments + 1] = match:sub(2, -2)
else
curString = curString..c
end
elseif (c == splitKey and curString ~= "") then
arguments[#arguments + 1] = curString
curString = ""
else
if (c == splitKey and curString == "") then
continue
end
curString = curString..c
end
end
if (curString ~= "") then
arguments[#arguments + 1] = curString
end
return arguments
end;
print(ExtractArgs("argument \"some argument\"", " "))
So what's the issue?
I am wondering for better ways. This current way, doesn't allow me to use " as it is being used to process.
Here is another way: Extract substring inbetween quotation marks, but skip \" and turn it into " instead in Lua
but I am wondering if there are even better ways.
Ways that would allow me to have something like this:
argument " argument2" "some argument" "some argument with a quotation mark " inside of it" another_argument"
to turn into something like this
> [1] = 'argument'
> [2] = 'argument2"'
> [3] = 'some argument'
> [4] = 'some argument with a quotation mark " inside of it'
> [5] = 'another_argument"'
The example that I made right now, might sound impossible because of no character really indicating what should be processed and what not.
But I am looking for better ways to extract substrings as arguments while allowing to have arguments as one argument that would normally just get split into arguments.
So if it wouldn't be for the ", \"some arguments\" would have just splitted into "some" and "arguments" instead of "some arguments".
Maybe a method that uses something like Lua does with ' " could be a way.
Because it would be probably impossible to have a perfect working system, that would turn this input """ into " as an extracted argument. I would imagine it just extracting it into this "", an empty string.
However, not if it would look like this '"'. But then the other question would be, how could you allow ''' to extract into '. I would imagine it working if it would be so "'". But this is getting too complicated.
I am wondering, is there even a better way to extract arguments, but allow certain special operation like keeping multiple arguments into one argument, by wrapping it around something, or just in any way?

how to ensure a user input contains at least one uppercase, lowercase, symbol, and number in ruby

I want to ensure that a password a user enters is at least 7 characters long and has at least one uppercase letter, one lowercase letter, one number, and one symbol.
The code seems to pass through the if loop until the symbol argument where it gets stuck.
puts "Please enter your desired password: "
password = []
pass_clear = ()
while pass_clear == (nil) do
password = gets.to_s.chomp
if password.length < 7
puts "Your password must contain at least seven characters."
elsif password.count("a-z") == password.length
puts "Your password must contain at least one uppercase character."
elsif password.count("A-Z") == password.length
puts "Your password must contain at least one lowercase character."
elsif password.count("!","#","#","$","%","^","&","*","(",")","_","-","+","=") < 1
puts "Your password must contain at least one symbol."
elsif password.count("0","1","2","3","4","5","6","7","8","9") < 1
puts "Your password must contain at least one number."
else
puts "Thank you, your account is complete."
pass_clear == 1
end
end
This is the output:
Please enter your desired password:
frank
Your password must contain at least seven characters.
Please enter your desired password:
frankie
Your password must contain at least one uppercase character.
Please enter your desired password:
Frankie
Your password must contain at least one symbol.
Please enter your desired password:
Frankie$
Your password must contain at least one symbol.
Please enter your desired password:
And it continues looping through the symbol stage regardless of how many symbols there are.
How can I ensure these symbols are recognized so the loop can finish?
You are quoting each of the symbols which is incorrect. You also have to escape the - and ^ characters
password.count("!##$%\\^&*()_\\-+=")
works for me in this example.
You'll also need to use a range for your numbers like:
password.count("0-9")
The - character is used for the ranges like "a-z" so it has to be escaped, the carat ^ is used to negate a count so:
password.count("^a-z")
would return a count of everything that wasn't in the range of a-z.
This can come in handy as you may want to prevent certain characters from being in your password strings. You could do something like:
password.count("^a-zA-Z!##$%\\^&*()_\\-+=0-9)
This would count any other characters outside what you've defined so you would want to get a zero return value to know they didn't use any forbidden characters.
Some further clarification on ranges in count(). The term "range" should not be confused with the Ruby class "Range". The class of Range uses ".." or "..." for the intervening items. In the count() method the range being considered is the ASCII range from the first character's ASCII number to the second character's ASCII number. That's why in my original typo of A-z it was counting ASCII 65 ("A") to ASCII 122 ("z") which happens to include the characters ASCII 92 to 96 which are not letters but \ ] ^ _ `
One option is to use a regex that contains four positive lookaheads, all of which operate from the beginning of the string.
R = /
(?=.*\p{Ll}) # match lowercase letter
(?=.*\p{Lu}) # match uppercase letter
(?=.*\d) # match digit
(?=.*[#{Regexp.escape("!##$%^&*(,)_+=-")}]) # match special char
/x # free-spacing regex def mode
def password_ok?(str)
str.match?(R)
end
password_ok? "aA1#" #=> true
password_ok? "A1#" #=> false
password_ok? "a1#" #=> false
password_ok? "aA#" #=> false
password_ok? "aA1" #=> false

Making ruby calculator run continuously

I have made a simple calculator in ruby. However after running once the program stops and has to be re-run. I tried the following but it ended in an infinite loop. How can I write this so that it will run until the users tells it to quit?
puts "Please enter two digits separated by operation you would like to calculate:"
input = gets.chomp.split(' ')
while input != nil
if input[1] == "+"
puts input[0].to_i + input[2].to_i
elsif input[1] == "-"
puts input[0].to_i - input[2].to_i
elsif input[1] == "*"
puts input[0].to_i * input[2].to_i
else
puts input[0].to_i / input[2].to_i
end
end
split(' ') returns an array and not nil, so input != nil always evaluates to true, which makes an infinite loop.
You may want to try while input.size == 2, or break the while loop at certain input like:
while true
# ... if / elsif for operators
elsif input[1] == 'exit'
break # end the 'while' loop
end
end
make changes like below:
msg = "Please enter two digits separated by operation you would like to calculate:"
puts msg
while input = gets.chomp.split(' ')
if input[1] == "+"
puts input[0].to_i + input[2].to_i
elsif input[1] == "-"
puts input[0].to_i - input[2].to_i
elsif input[1] == "*"
puts input[0].to_i * input[2].to_i
else
puts input[0].to_i / input[2].to_i
end
puts msg
end
This whole thing is a big mess of Ruby that can be drastically simplified by degrees. The key here is to apply the Ruby way to things and elegant solutions become immediately obvious.
Consider replacing that messy while loop with an actual loop structure. Also name the elements resulting from the split based on their meaning to you:
loop do
puts "Please enter two digits separated by operation you would like to calculate:"
left, operator, right = gets.chomp.split(' ')
result = case (operator)
when '+'
left.to_i + right.to_i
when '-'
left.to_i - right.to_i
when '*'
left.to_i * right.to_i
when '/'
left.to_i / right.to_i
end
puts result
end
Now this looks like a lot of repetition, the only thing changing here is the operator. Since Ruby is a highly dynamic language we can actually collapse this some more:
loop do
puts "Please enter two digits separated by operation you would like to calculate:"
left, operator, right = gets.chomp.split(' ')
result = case (operator)
when '+', '-', '*', '/'
left.to_i.send(operator, right.to_i)
end
puts result
end
Now there's still some duplication here. What about trying to reduce this further and also allow for more flexibility:
loop do
puts "Please enter digits separated by the operations you would like to calculate:"
values = gets.chomp.split(' ')
while (values.length > 2)
left = values.shift.to_i
operator = values.shift
right = values.shift.to_i
values.unshift(left.send(operator, right))
end
puts values[0]
end
That means you can have arbitrarily long lists of numbers to add together. It's not much harder to make this tokenize your string into numbers and non-number components, but that's something you can try on your own.
A recursive approach:
def recurs_calc
puts "Please enter two digits separated by operation you would like to calculate:"
input = gets.chomp.split(' ')
if input[1] == "+"
puts input[0].to_i + input[2].to_i
recurs_calc
elsif input[1] == "-"
puts input[0].to_i - input[2].to_i
recurs_calc
elsif input[1] == "*"
puts input[0].to_i * input[2].to_i
recurs_calc
elsif input[1] == '/'
puts input[0].to_f / input[2].to_i
recurs_calc
elsif input[0] == 'exit'
exit
else
puts 'please enter two numbers with SPACES i.e. 4 + 4 then enter'
recurs_calc
end
end
recurs_calc
Here we recall recurs_calc as per conditions and exit when the user types 'exit'. Note I've also used to_f in the / branch to get a more accurate result and included a final branch that takes into account an 'incorrect' input. Try running it.
Just another approach using eval that you may find helpful although this is probably cheating a bit. Also it's considered bad practice to use eval for security reasons. Also a special thanks to #nicael for the string substitution:
loop do
puts "Enter calculation"
input = gets.chomp
if input == 'exit'
exit
else
p eval (input.gsub(/(\d+)/, '\1.0'))
end
end

Issue with code not running after user provides input

I am in my first year of coding. I am writing a program for school that I currently am having some issues with. The assignment is to create a trivia game using files. My code won't continue after I ask the user for an input to determine how many points the question they are asked will be worth. The section of the code with the problem is posted directly below. My entire program is below that in case that help anyone needs to see the whole thing. Just for the record the entire program is not finished yet.
P.S I am new at this so if I missed something obvious I apologize.
while repeat3==True:
#identifying what point value the player wants
print "what point value do you want the question to have?"
print "your options are:200,400,600,800,1000"
desiredValue=input()
print 'testing'
if desiredValue==200:
questionValue=random.randint(1,5)
repeat3=False
elif desiredValue==400:
repeat3=False
questionValue=random.randint(5,9)
elif desiredValue==600:
repeat3=False
questionValue=random.randint(8,13)
elif desiredValue==800:
repeat3=False
questionValue=random.randint(13,17)
elif desiredValue==1000:
repeat3=False
questionValue=random.randint(17,20)
else:
print 'please entre one of the good values'
#asking the user the question
print "Here is the question:"
print temporaryQuestions[currentCategory][questionValue]
here is my entire program so far
#quiz Master Project
#imports
import random
import time
#variables defined
categorys=["history", "vintage tv", "harry potter", 'mythology']
questionFiles=['history questions.txt','vintage tv show
questions.txt','HarryPotterQuestions.txt','mythQuestions.txt']
answerFiles=['history answers.txt','vintageTVAnswers.txt','HarryPotterAnswers.txt','mythAnswers.txt']
chosenCategory=0
HistoryQuestionsList=[]
TVQuestionsList=[]
HarryPotterQuestionsList=[]
MythQuestionsList=[]
temporaryQuestions=[HistoryQuestionsList,TVQuestionsList,HarryPotterQuestionsList,MythQuestionsList]
repeat1=True
repeat2=True
repeat3=True
desiredValue=0
name=0
# functions
#_______________________________________________________________________________
#turning the questions into lists
#history questions
a= open ('history questions.txt','r')
reader1=a.readlines()
for line1 in reader1:
HistoryQuestionsList.append(line1)
#vinatage tv
b= open('vintage tv show questions.txt','r')
reader2=b.readlines()
for line2 in reader2:
TVQuestionsList.append(line2)
#Harry potter
c=open('HarryPotterQuestions.txt','r')
reader3=c.readlines()
for line3 in reader3:
HarryPotterQuestionsList.append(line3)
#Mythology
d=open('mythQuestions.txt','r')
reader4=d.readlines()
for line4 in reader4:
MythQuestionsList.append(line4)
#prompting
print "hello and welcome to (for copyright reasons) japordy!"
print
print "what is your name?"
name=raw_input()
print
print "you are going to be able to chose from a few types of questions to answer"
time.sleep(.2)
print
print "you will be asked 10 questions"
time.sleep(.2)
print
print "first you need to decide what catagory to get a question from then, select a question on the basis of points."
time.sleep(.2)
print
print "you may chose from a different catagory each time"
time.sleep(.2)
print
print "after you are asked a question that question will be deleted from the questions that you can possibly get"
time.sleep(.2)
print
print "the point system works like this, if you get a question right you will be given the total number of points that question was worth."
print "But if you get the question wrong you will be fined the number of points that the question was worth."
print "if you take to long to answer you will not get a chance to answer and you will not recieve or be fined points"
time.sleep(3)
print
print "the catagories that you can chose from are: history, vintage tv, harry potter, and mythology"
time.sleep(.2)
print
print "the point values are 200, 400, 600, 800, and 1000"
print
#selecting the questions that will be asked
print "please entre the catagory you want to choose"
chosenCategory=raw_input()
chosenCategory=chosenCategory.lower()#converting all the letters to lowercase
#seeing if the user entered a valid category and if so creating a file that can be used for each round.
while repeat1==True:
while repeat2==True:
for i in range(1,5):
if chosenCategory==categorys[i-1]:
currentCategory=i-1
repeat2=False
if repeat2!=False:
#selecting the questions that will be asked
print "the catagories that you can chose from are: history, vintage tv, harry potter, and mythology"
print
print "please entre the catagory you want to choose"
chosenCategory=raw_input()
chosenCategory=chosenCategory.lower()#converting all the letters to lowercase
while repeat3==True:
#identifying what point value the player wants
print "what point value do you want the question to have?"
print "your options are:200,400,600,800,1000"
desiredValue=input()
print 'testing'
if desiredValue==200:
questionValue=random.randint(1,5)
repeat3=False
elif desiredValue==400:
repeat3=False
questionValue=random.randint(5,9)
elif desiredValue==600:
repeat3=False
questionValue=random.randint(8,13)
elif desiredValue==800:
repeat3=False
questionValue=random.randint(13,17)
elif desiredValue==1000:
repeat3=False
questionValue=random.randint(17,20)
else:
print 'please entre one of the good values'
#asking the user the question
print "Here is the question:"
print temporaryQuestions[currentCategory][questionValue]
UserAnswer=raw_input
For Python2, input () may not work. Use raw_input () if this is the case. Secondly, input is a string but you are comparing it with an integer. (1 is 0+1 or 2-1 but "1" is a stick and "2" is load of pixels that look like a swan swimming to the left. You can either compare it to "200" or compare int(desired_value) with 200.
Also, you might want to look at switch(),case,default for this or, since the code is almost identical in each case, an associative array of min/max values:
randMinMax = {200: {1,5}, 400: {5,9} ...}
while True: #infinite loop - see 'break' below
desired_input = int(raw_input) #Might want to try/catch in case of bad input
if desired_input in randMinMax:
questionValue=random.randint(randMinMax [desired_input][0], randMinMax [desired_input][0])
break; # Break out of loop
else:
print 'please entre one of the good values'
However, there is an even quicker version in this case since there is a fixed relationship between the input value and the random limits so:
limit = (desired_input / 200) - 1 # 0 to 4 inclusive
if limit==int(limit) and limit < 5: # not, for example, 215
limit = (limit * 4) + 1 # 1, 5, 9, 13, 17
questionValue=random.randint(limit,math.min (limit+4, 20)) # Because the last limit is 20, not 21 - hence math.min
break; # Got a result, stop looping.
A little more than you asked but these principals should help you along as you learn to code. Good luck and enjoy!

Giving users a certain amount of tries until program exits

I'm creating a method where the user puts in a "PIN" number to access different methods.. Yes it's an ATM..
I'm trying to figure out how to make it so that the user gets a specific amount of tries until the program exit's..
After a bunch of research I haven't very well found anything useful.. The only thing I've found is to use .to_s.split(//) in order to add the number of the try into an empty array. Which doesn't make sense to me because why would you make an integer into a string..?
So my question is, how do you make it so that users only have a certain amount of tries, 3, until they get kicked out of the program?
Main source:
#!/usr/bin/env ruby
################
#ATM Rewrite
#
#Creator Lost Bam Not completed yet.
#
#11/19/15
##################
require_relative 'checking.rb'
require_relative 'savings.rb'
require_relative 'exit.rb'
require_relative 'loan.rb'
require_relative 'transfer.rb'
require_relative 'redirect.rb'
class ATM
attr_accessor :name, :checking_account, :savings_account, :pin_number, :transfer, :loan
def initialize( name, checking_account, savings_account )
#name = name
#checking_account = checking_account
#savings_account = savings_account
#pin_number = pin_number
end
end
##############
def pin
x = []
puts "Enter PIN Number:"
input = gets.chomp.to_i
if input == 1234
menu
else
x += 1.to_s.split(//) #<= This is what I found to convert integer to Array
puts "Invalid PIN, try again:"
input = gets.chomp
if x == 3
bad_pin
end
end
end
############
def menu #add #{name} on line 41
puts <<-END.gsub(/^\s*>/, ' ')
>
>Welcome thank you for choosing Bank of Bam.
>You may choose from the list below of what you would like to do
>For checking inquiries press '1'
>For savings account information press '2'
>To transfer funds press '3'
>To either apply for a loan, or get information on a loan press '4'
>To exit the system press '5'
>
END
input = gets.chomp
case input.to_i
when 1
checking_information
when 2
savings_information
when 3
transfer_funds
when 4
loan_info
when 5
exit_screen
else
puts "Invalid option please try again"
menu
end
end
def bad_pin
abort('Invalid PIN exiting sytem..')
exit
end
pin
Tried something new:
def pin
x = 3
puts "Enter PIN(#{x} attempts left):"
pin_num = gets.chomp
case pin_num.to_i
when 1234
menu
else
puts "Invalid PIN"
x -=1
return pin
if x == 0
bad_pin
end
end
end
It doesn't increment the number down it just keeps saying 3 tries left:
Enter PIN(3 attempts left):
4567
Invalid PIN
Enter PIN(3 attempts left):
45345
Invalid PIN
Enter PIN(3 attempts left):
6456
Invalid PIN
Enter PIN(3 attempts left):
4564
Invalid PIN
Your problem is that every time you recall the method the value of x resets again. You need to have a loop inside the pin method that'll keep track of attempts.
def pin
x = 3
while (x > 0) do
puts "Enter PIN(#{x} attempts left):"
pin_num = gets.chomp
case pin_num.to_i
when 1234
menu
else
puts "Invalid PIN"
x -=1
puts "no tries left" if x == 0
break if x == 0
end
end
end
Stay in the method. Recalling the method starts you back at three attempts.

Resources