Avoid printing identical output - python

I am making a troubleshooting program, which will ask the user for an input, search through some lists to find the problem and give them a solution.
f=open('problem.txt')
lines=f.readlines()
problem1 = ["cracked", "phone", "screen", "dropped"]
problem2 = ["charging", "port", "phone"]
problem3 = ["slow", "phone", "freeze"]
problem_input = input ("What is your problem? ")
list_split = (problem_input.split( ))
for i in problem1:
if i in list_split:
print (lines[0])
for i in problem2:
if i in list_split:
print (lines[1])
But if i input, "my phone is cracked", the output will be printed twice. How do I only print this once?

You're cycling through a list of problem cases and your input matches twice. The matches are "phone" and "cracked". To prevent that, stop at the first match like that:
for i in problem1:
if i in list_split:
print (lines[0])
break
The break keyword will quit the cycle.

You are looping through your "problems" lists and getting multiple matches for your condition.
You could return your matched problem by making this into a function:
f=open('problem.txt')
lines=f.readlines()
problem1 = ["cracked", "screen", "dropped"]
problem2 = ["charging", "port"]
problem3 = ["slow", "freeze"]
problems = [problem1, problem2, problem3]
def troubleshoot():
problem_input = input("What is your problem? ")
list_split = (problem_input.split())
for idx, problem in enumerate(problems, 1):
if any(i in problem for i in list_split):
return "problem{}".format(idx)
# or return lines[0]
It would run as the following:
>>> troubleshoot()
What is your problem? my phone is slow and freezing up
'problem3'
>>> troubleshoot()
What is your problem? my phone is not charging
'problem2'
>>>
>>> troubleshoot()
What is your problem? my phone dropped and the screen is cracked
'problem1'
Alternatively, if there isn't a reason for having "phone" in each of the problem lists, you might be better off using a dict here:
problems = {'cracked':1, 'screen':1, 'dropped':1,
'charging':2, 'port':2,
'slow':3, 'freeze':3}
user_problems = {problems[i] for i in problem_input.split()}
Note: I removed "phone" from both of these because it matches for every list

Related

Deciphering script in Python issue

Cheers, I am looking for help with my small Python project. Problem says, that program has to be able to decipher "monoalphabetic substitute cipher", while we have complete database, which words will definetely (at least once) be ciphered.
I have tried to create such a database with words, that are ciphered:
lst_sample = []
n = int(input('Number of words in database: '))
for i in range(n):
x = input()
lst_sample.append(x)
Way, that I am trying to "decipher" is to observe words', let's say structure, where different letter I am assigning numbers based on their presence in word (e.g. feed = 0112, hood = 0112 are the same, because it is combination of three different letters in such a combination). I am using subprogram pattern() for it:
def pattern(word):
nextNum = 0
letternNums = {}
wordPattern = []
for letter in word:
if letter not in letterNums:
letternNums[letter] = str(nextNum)
nextNum += 1
wordPattern.append(letterNums[letter])
return ''.join(wordPattern)
Right after, I have made database of ciphered words:
lst_en = []
q = input('Insert ciphered words: ')
if q == '':
print(lst_en)
else:
lst_en.append(q)
With such a databases I could finally create process to deciphering.
for i in lst_en:
for q in lst_sample:
x = p
word = i
if pattern(x) == pattern(word):
print(x)
print(word)
print()
If words in database lst_sample have different letter length (e.g. food, car, yellow), there is no problem to assign decrypted words, even when they have the same length, I can sort them based on their different structure: (e.g. puff, sort).
The main problem, which I am not able to solve, comes, when word has the same length and structure (e.g. jane, word).
I have no idea how to solve this problem, while keeping such an script architecture as described above. Is there any way, how that could be solved using another if statement or anything similar? Is there any way, how to solve it with infortmation that words in lst_sample will for sure be in ciphered text?
Thanks for all help!

How strip python

I'm writing a quiz code for school. The code iterates over a text file and loads the questions and answers from it. The user will select a difficulty to do the quiz on. The number of options for answers will vary depending on the difficulty. I have split each question and possible answer in the text file with commas.
from random import shuffle
file = open("maths.txt" , "r")
for line in file:
question = line.split(",")
print(question[0])
if difficulty in ("e", "E"):
options = (question[1], question[2])
if difficulty in ("m", "M"):
options = (question[1], question[2], question[3])
if difficulty in("h", "H"):
options = (question[1], question[2], question[3], question[4])
options = list(options)
shuffle(options)
print(options)
answer = input("Please enter answer: ")
if answer in (question[1]):
print("Correct!")
else:
print("incorrect")
file.close()
This is what a line of the text file would look like:
Question 1. What is 4+5?,9,10,20,11
The first option (question[1]) will always be the correct answer, therefore I would like to shuffle the options. With this code the options are outputted with square brackets, newline characters and quotation marks. Does anyone know how I can strip these? I tried to use: line.split(",").strip() however this seemed to do nothing at all. Thanks
The problem is that you are trying to print a list object. Instead, you should print each option. you'd probably be better printing some formatting around it:
for option_num, option in enumerate(options):
print("{} - {}").format(option_num, option)
please read about enumerate and format to understand exactly what happens here
Something like this?
from random import shuffle
def maths_questions():
file = open("maths.txt" , "r")
for line in file:
question = line.strip().split(",") # every line in file contains newline. add str.strip() to remove it
print(question[0])
if difficulty in ("e","E"):
options = [question[1],question[2]]
elif difficulty in ("m","M"):
options = [question[1],question[2],question[3]]
elif difficulty in("h","H"):
options = [question[1],question[2],question[3],question[4]]
# why to create tuple and then convert to list? create list directly
shuffle(options) #shuffle list
print("Options: ", ", ".join(options)) # will print "Options: opt1, opt2, opt3" for M difficulty
answer=input("Please enter answer: ")
if answer in (question[1]):
print("Correct!")
else:
print("Incorrect, please try again...")
file.close()
Python docs:
str.join(iterable)
Return a string which is the concatenation of the strings in iterable. A TypeError will be raised if there are any non-string values in iterable, including bytes objects. The separator between elements is the string providing this method.
for option in options:
print(option)
To remove characters from a string, use .rstrip("put text to remove here") to remove characters from the right end of the string and .lstrip("text to remove") to remove characters from the left of the string.

How do you output a list out without quotes around strings?

I'm trying to set up a block to accept only inputs that are in a list but first it asks for the inputs in the input function but I can't seem to get rid of the quotes around the strings in the list. Here is some example code:
def Sinput(acceptable):
while True:
acceptable = [str(i) for i in acceptable]
a = input('Enter'+str(acceptable[:-1]).strip('[]')+' or '+str(acceptable[-1]+': '))
if a in acceptable:
return a
break
a = Sinput([ 1, 2.01, '\'cat\'', 'dog'])
print('you entred:', a)
The input asks: Enter'1', '2.01', "'cat'" or dog: I want it to ask: Enter 1, 2.01, 'cat' or dog:
Using .replace('\'', '') won't work because the input 'cat' would no longer display correctly
Thanks for any help, I've only been doing coding for about a week.
Use .join(...) which is the recommended way for joining an iterable of strings:
a = input('Enter'+ ' ,'.join(acceptable[:-1]) + ...)
# ^^^^^^^^^
P.S. I don't see why you need a break after that return statement.
I think this would do good for you:
a = input('Enter {} or {}'.format(' ,'.join(acceptable[:-1]), acceptable[-1]))

How to find keywords in a file using module re

I am looking to make a program that can pick out car information from a file using module re. The user is asked questions about the car that he wants to view and if the input is not in the file I should display an error message and loop the code again if the user wants to. I am having difficulty trying to find the inputs in the file: this is the code so far:
import re
import random
myList = ([])
car = input("What car do you want to view?");
myList.insert(1, car)
model = input("What car model is it of");
myList.insert(2, model)
fuelTy = input("What fuel type is it: diseal or petrol");
myList.insert(3, fuelTy)
engSize = input("What engine size is it : eg 2l");
myList.insert(4, engSize)
rnd = (int(random.randrange(50000000)) + 1)
with open("car.txt", "r") as carfile:
for line in carfile:
if all(myList.lower() in re.findall('\w+', line.lower()) for myList in carfile):
splitted_line = line.split(':')
print(splitted_line)
if not myList not in carfile:
print("We don't have the car available currently. Please contact the head office with the case number " + str(rnd))
Cho2 = input("Would you like to see anything yes or no").lower
if Cho2 == "yes":
print("OK")
elif Cho2 == "no":
print("End of program")
Text file is:
bmw : X6 : 3.4l : Engine size 4395cc: petrol: 0-62mph in 4.8s: gear type automatic : 5 doors : economy 29mpg : top speed 155 mph
audi : Q7 : 3.0l : Engine size 2967cc: disel: 0-62mph in 6.5s: gear type automatic : 5 doors : economy: 48mpg : top speed 145 mph
honda : CRV : 2.0l: Engine size 1997cc: petrol : 0-62mph in 10.0s: gear type manual : 5 doors : economy 30mpg : top speed 18 mph
if all(myList.lower() in re.findall('\w+', line.lower()) for myList in carfile):
In this line, you are re-defining myList to be a line in the file. But you have an outer loop (for line in carfile) that does the same thing.
Change this to eliminate the for expression, and you'll be on the right track:
if all(myList.lower() in re.findall('\w+', line.lower())):
FWIW, this is going to be very hit-or-miss, because you have things like engine size that use different measures (cc vs. l) in the file.
Next, please be aware that you can (and probably should, as a matter of avoiding errors) use .append() in order to grow a list, instead of .insert(). The difference is that append does not require you to keep track of an index, which in cases like this is not benefiting you (you don't make use of the position information at any time) and is a source of error if you copy/paste a block of code to add a new field.
myList.append(engSize) # was myList.insert(4, engSize)
Also, you should probably give users the option of not entering a field, and skip searching if they don't enter it. (Just don't append the field if it's empty, perhaps?)
engSize = input("What engine size is it : eg 2l")
if engSize: myList.append(engSize)
EDIT
Okay, just got done for the day, back to this program. :-)
There are some more problems, but let's take care of the "all requires an iterableissue first. If you look at the docs for [all`](https://docs.python.org/3/library/functions.html#all), it says
all(iterable)
So we need to restructure the test to give all an iterable (a list, tuple, view, or other expression that can be iterated), or we need to stop using all.
Well, we are trying to iterate over myList, so it should be possible to come up with an iterable. Let's start with that in mind:
if all(s for s in myList):
In fact, we can put the .lower() back in - that made sense. So:
if all(s.lower() for s in myList):
Now, let's treat s.lower() as a word (which it is) and search for it in the input line. What we are doing is converting our previous string expression, s.lower(), into a boolean expression: word in list, within the context of the iteration we already have. This will be a different flavor of the in keyword:
if all( (EXPR) for s in myList):
if all((s.lower() in re.findall('\w+', line.lower())) for s in myList):
When I make this change, I can match the make of the car.
There are some problems with the logic, as well. You want to match the user query to a car type. If you can't match that, then you want to print a message about "We don't have the car ..." But you can't get that test (not matching) in one line. If you could get that test into one line, you could probably get the searching part into one line as well. (Not always, but it's worth looking!)
Instead, just keep track of whether or not you found the car:
found_car = False
for line in carfile:
if ...
found_car = True
break
if not found_car:
print("We don't have the car ...")
Next, let's make the program run longer (for testing if nothing else). You are doing for loops, so I assume you can do a while loop. Let's add a loop around the whole thing to keep going until the user types quit:
while True:
make = input("What make of car do you want (or type 'quit')? ")
if make == 'quit':
break
if make:
myList.append(make)
Finally, let's take a look at your regular expression. You are using \w+, which will match "word characters" (whatever those are) one or more times.
That's a good start for things like "audi" and "honda", but word characters don't include the period ('.') or the hyphen ('-'), both of which appear in your data.
Instead, try changing your regex to match either a word character or a dot, one or more times:
re.findall('[\w.]+', ...)
Good luck!
You have bugs!
First, you are initializing myList = ([]) as a tuple containing a single empty list, so append() or insert() aren't going to work. Try myList = [].
Second, you're getting the indexes wrong in your myList.insert(...) statements. Just use myList.append(...) instead, no need to worry about indexes that way.
Then, try replacing (not tested...):
if all(myList.lower() in re.findall('\w+', line.lower()) for myList in carfile):
... with:
if all (item.lower() in re.findall('\w+', line.lower()) for item in myList):
A simple optimization which also makes the code more readable:
line_words = set(re.findall('\w+', line.lower()))
if all(item.lower() in line_words for item in myList):

program to read data from a text file and display the output in abbreviated form with all punctuation marks as entered my the user

the text file looks like: textabbrv.txt
r:are
u:you
ttyl:talk to you later
l8:late
brb:be right back
i tried a lot to fix this, but there is one error, my program is:
def main():
indexEntries={}
infile=open('textabbrv.txt','r')
fields=extractRecord(infile)
while len(fields)>0:
set_entries(indexEntries,fields[1],fields[0])
fields=extractRecord(infile)
infile.close()
printIndex(indexEntries)
def extractRecord(infile):
line=infile.readline()
if line!="":
fields=line.split(":")
page=fields[0].rstrip()
term=fields[1].rstrip()
return [page,term]
else:
return []
def set_entries(entries,term,page):
pageSet=set([page])
entries[term]=pageSet
def printIndex(entries):
user_input=input("Enter a message to be translated: \n")
if user_input!=" ":
user_split=user_input.replace(","," ").replace("?"," ").replace("!"," ").\
replace(":"," ").replace(";"," ").split(" ")
print()
print("The translated text is: ")
for long_form in entries:
sentence=entries[long_form]
for short_form in sentence:
if short_form in user_split:
print(user_input.replace(short_form,long_form))
main()
OUTPUT:
Enter a message to be translated:
ttyl,brb
The translated text is:
talk to you later,brb
ttyl,be right back
but the output should look like this and should be translated in just one line, i think i messed up somewhere in the for loops a the end of the program
Enter a message to be translated:
ttyl,brb
The translated text is:
talk to you later,be right back
First of all, the output you see is due to this:
print(user_input.replace(short_form,long_form))
Whenever you find a match, you replace that match in the original user input, and print it out, but you don't store that modified version of the original input at all.
You could fix that by doing:
user_input = user_input.replace(short_form,long_form)
and then printing the new version of user_input at the end of printIndex. Now, that may be problematic, but that's another story.
In any case... the way you have approached this is a bit unusual. You are populating the indexEntries dictionary in the reverse way that I would expect. You put the indices as the values! Instead:
1) I would import csv and rewrite this:
infile=open('textabbrv.txt','r')
fields=extractRecord(infile)
while len(fields)>0:
set_entries(indexEntries,fields[1],fields[0])
fields=extractRecord(infile)
infile.close()
as:
with open('textabbrv.txt','r') as infile:
for (field1, field2) in csv.reader(infile, delimiter=':'):
indexEntries[field1] = field2
In the process I'm getting rid of extractRecord and set_entries. Now the dictionary looks like {'brb': 'be right back', 'r': 'are, ...}
2) You're splitting the user input, but then you don't make use of that. Let's rewrite this:
for long_form in entries:
sentence=entries[long_form]
for short_form in sentence:
if short_form in user_split:
print(user_input.replace(short_form,long_form))
and make it:
output = []
for word in user_split:
# The following could be written as
# output.append(entries.get(word, word))
if word in entries:
output.append(entries[word])
else:
output.append(word)
print ','.join(output)

Categories