Thomas Beaudet Thomas Beaudet - 5 months ago 11
Python Question

Best way to perform string validation with user input in Python 3.4?

I have got a string as is:

line = 'City' /* City can be in 2 or 3 parts */


----> 2 parts: first char of each part is a capital letter.

----> 3 parts: first char of 1st and 2nd part is a capital letter.

The line i get is always valid because i check it with a regex already,
I now would like to know what is the best way to ask the user for a character, then check if the input is the same as the City's first character (no matter what part of the city), if it is, print the City name to the output.

I am doing this for now but i'm learning Python for 2 days now and i'm kind of struggling right now.

line_ = "Mont de Marsan"

while True:
inp = input('')
if 'ABORT' in inp:
inp = False
sys.exit(0)
else:
inp = input('')
for c in line_:
if inp == c:
print (line_)
else:
inp = False
sys.exit(0)
break


I hope the description of my problem is straight forward because it's getting messy in my mind :)

Could you please help me find the best way to perform such things in real time and for a lot of strings ?

/* EDIT */


expected behaviour of programm if City is 'Pont de Marsan'

<---- d
----> Mont de Marsan
<---- P
----> Pont de Marsan
<---- M
----> Mont de Marsan
<---- l
programm exit.

jDo jDo
Answer

"(...) if the input is the same as the City's first character (no matter what part of the city)"

You can split the city name by space using the string method split() to get a list of its parts:

>>> "Mont de Marsan".split() == ["Mont", "de", "Marsan"]
True
>>>

split() defaults to splitting by space but can split one string by any other string, e.g.

>>> "abc".split("b") == ['a', 'c']
True
>>> 

You can then go through each part of the city name and check what it starts with using the startswith() method or string indexing if you only want a specific number of letters; e.g. "Paris"[0] to match only the first letter "P".

You didn't mention it but I assume you also want case-insensitive matching so that both "p" and "P" will match "Paris", "Pont Neuf" and "pont neuf". To do this, you could simply convert your city names and the user input to the same case using lower() or upper() but since you're using Python 3.x, you might as well take advantage of the casefold() method that's made for this purpose. From the docs:

Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string. For example, the German lowercase letter 'ß' is equivalent to "ss". Since it is already lowercase, lower() would do nothing to 'ß'; casefold() converts it to "ss".

In the snippet below, you're converting the user input to a boolean (it starts out as a string). There's nothing technically wrong in it - Python won't complain - but is it really what you want?

inp = input('')      <-- a string
if 'ABORT' in inp:   <-- still a string
    inp = False      <-- a boolean

Maybe you wanted to break the while loop using a boolean? In that case, you could do the following:

done = False

while not done:
    inp = input('') 
    if 'ABORT' in inp:
        done = True
    ...

sys.exit(0) 

The code above also eliminates the need to repeat sys.exit(0) throughout the code.

An edited version of your code. I might have changed it a bit too much but just use what you can:

import sys

cities = ("Mont de Marsan", "Pont Neuf", "Paris")

done = False

while not done:
    inp = input('> ')                                                                                
    if any(inp):
        if 'ABORT' in inp:
            done = True
        else: 
            inp = inp.casefold()
            for city in cities:
                for part in city.casefold().split():
                    if part.startswith(inp):
                        print(city)
                        break
    else:
        done = True

sys.exit(0)

I saved the code in a script called suggestions.py. Testing it...

$ python3 suggestions.py 
> p
Pont Neuf
Paris
> P
Pont Neuf
Paris
> PAR
Paris
> AR
> DE
Mont de Marsan
> de
Mont de Marsan
> d
Mont de Marsan
> D
Mont de Marsan
> 
Comments