BhupinderSD BhupinderSD - 3 months ago 10x
Python Question

Making sure a response is given from csv

I am having a problem with a project I'm currently working on. My project is to take a user's query about a problem that they are having with their phone and the program searches for keywords in a csv file. If it finds a keyword in the csv, it prints a linked answer.

This is the code:

import csv

Problem = input("What is wrong with your device? ").lower()

Words = Problem.split(" ")

Reader = csv.reader(open("answers2.csv"))

Plist = [row for row in Reader]

Solved = False

for x in range (0, len(Words)):
for y in range (0,len(Plist)-1,2):
if(Words[x]in Plist[y]):
Solved = True

file can be found on pastebin and google drive.

The problem is that the question can be skipped and the program closes. Also, if a word from the query is not found in the csv, there is no response and the program closes. I would like the question to not be skipped and for the program to ask the user to enter the problem again or to 'contact the supplier'.

I am completely open to suggestions on how to achieve this and I do not mind if everything is changed around. Also, if there is a better way to get the results that I want, please tell me.


You get no response because there is no code to display anything when a word is matched nor when there weren't any. In other words—at the very least—you need to add one or more calls to print() based on whether Solved is True or not after the for loops end. i.e. Use an if/else.

I also strongly suggest you read (and follow) the PEP 8 - Style Guide for Python Code.

I've rewritten your code following the referenced style guidelines and more-or-less doing what I suggested. One major change was made to what gets stored in plist. Instead of what you had (a list of keywords followed by list of one item containing the answer), each pair of items in it is now comprised of a (single) set of keywords to match followed by the text of the matching answer in the next entry. In other words, the first couple of pairs of entries in plist are now:

[0]: {'dropped', 'screen', 'cracked', 'broken'}
[1]: "Please visit a verified retailer to fix your display. "
[2]: {'spill', 'water', 'coke', 'liquid', 'steam', 'beer', 'fanta', 'rain', 'wine', 'drink'}
[3]: "Turn your device off immediately and take out the SIM card, SD card, battery etc. Then leave the phone to dry. You can place the phone in a bag of rice or silica bags or in sunlight. Leave it at least 48 hours then it should work as normal. "
   etc ...

Making the keywords a set will make checking if a user word is in them much faster. Making the csv rows with just the answer in them a single value is just a minor simplification (so you don't need use a trailing [0] to access them).

The other significant change was to make the code that searches through the answers a separte function so it could easily be called multiple times if necessary.

Here's the complete result:

import csv

def find_answer(words, plist):
    for word in words:
        for i in range(0, len(plist)-1, 2):
            if word in plist[i]:
                return plist[i+1]
    return None

with open("answers2.csv") as ans_file:
    reader = csv.reader(ans_file)
    # read in rows of csv, processing even and odd rows differently
    plist = [row[0] if i%2  # odd rows have answer text in first value
             set(w for w in row if w)  # even rows are keywords to match
                for i,row in enumerate(reader)]

while True:
    problem = input("What is wrong with your device? ").lower()
    words = problem.split()
    if not words:
        print("Terminated by user.")
    answer = find_answer(words, plist)
    if not answer:
        print("No answer found. Try explaining using different words.")

Lastly, since the answer text can be fairly long, I suggest you consider changing the code to use the textwrap module to display it instead of simply "print(answer)".