使用Python 3.4中的用户输入执行字符串验证的最佳方法?

时间:2016-07-03 09:24:25

标签: python python-3.x

我有一个字符串:

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

----> 2部分:每个部分的第一个字母是大写字母。

----> 3部分:第1部分和第2部分的第一个字母是大写字母。

我得到的行总是有效的,因为我已经用正则表达式检查它, 我现在想知道询问用户角色的最佳方式是什么,然后检查输入是否与城市的第一个角色相同(无论城市的哪个部分),如果是,则打印城市名称到输出。

我现在正在这样做,但我现在正在学习Python 2天,现在我有点挣扎。

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

我希望对我的问题的描述是直截了当的,因为它在我的脑海里变得凌乱:)

你能帮我找到实时执行这些事情的最佳方式吗?

 /* EDIT */

如果City是'Pont de Marsan',程序的预期行为

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

以下是更多解释:

我有一个城市名单,有些可以是'巴黎',有些可以是'Mont de Marsan',甚至是'Pont Neuf'。我现在要问用户一个角色,如果他进入P,我必须打印'Paris'和'Pont Neuf',如果他进入'd'我必须打印'Mont de Marsan'。它与汽车中的GPS系统具有相同的行为。

2 个答案:

答案 0 :(得分:3)

  

“(...)如果输入与城市的第一个角色相同(无论城市的哪个部分)”

您可以使用字符串方法split()按空格拆分城市名称,以获得其list个部分:

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

split()默认按空格分割,但可以用任何其他字符串分割一个字符串,例如

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

然后,如果您只想要特定数量的字母,则可以浏览城市名称的每个部分并使用startswith()方法或字符串索引检查它的起始位置;例如"Paris"[0]仅匹配第一个字母“P”。

你没有提到它,但我假设你也想要不区分大小写的匹配,以便“p”和“P”都匹配“Paris”,“Pont Neuf”和“pont neuf”。要执行此操作,您只需使用lower()upper()将您的城市名称和用户输入转换为相同的案例,但由于您使用的是Python 3.x,因此您可以利用为此目的而制作的casefold()方法。来自the docs

  

Casefolding类似于小写,但更具攻击性,因为它   旨在删除字符串中的所有大小写区别。例如,   德语小写字母'ß'相当于"ss"。因为它是   已经小写,lower()'ß'无效; casefold()   将其转换为"ss"

在下面的代码段中,您将用户输入转换为布尔值(它以字符串开头)。它在技术上没有任何错误 - Python不会抱怨 - 但它真的是你想要的吗?

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

也许你想用布尔值打破while循环?在这种情况下,您可以执行以下操作:

done = False

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

sys.exit(0) 

上面的代码也消除了在整个代码中重复sys.exit(0)的需要。

您的代码的编辑版本。我可能已经改变了一点但只是使用你能做的事情:

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:
                city_casefold = city.casefold()
                if city_casefold.startswith(inp):
                    print(city)
                else:
                    for part in city_casefold.split():
                        if part.startswith(inp):
                            print(city)
                            break
    else:
        done = True

sys.exit(0)

我将代码保存在名为suggestions.py的脚本中。测试它......

$ 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
> 

答案 1 :(得分:2)

我的策略是创建城市名称集的字典,将城市名称中每个单词的首字母作为键。创建这个词典不需要很长时间,但它可以非常快速地找到匹配的城市。

我的输入循环忽略空字符串以及前导或尾随空格,如果找不到匹配则打印“Nothing matches”,因为我发现当程序关闭时非常令人讨厌我给了它不好的意见。

from collections import defaultdict

# Create list of city names
cities = '''\
Aix en Provence
Bordeaux
Clermont Ferrand
Le Mans
Le Havre
Limoges
Lyon
Marseille
Mont de Marsan
Montpellier
Nantes
Nice
Nîmes
Paris
Pont Neuf
Saint Denis
Saint Étienne
Strasbourg
Toulon
Toulouse
Tours
'''.splitlines()

# Build a dictionary of cities keyed by the
# 1st letter of each word of the city name
city_index = defaultdict(set)
for city in cities:
    for word in city.split():
        city_index[word[0]].add(city)

# Display the city index
for k in sorted(city_index.keys()):
    print(k, city_index[k])
print()

print('Select cities by an initial letter, or ABORT to quit')
while True:
    s = input('? ')

    #Remove leading or trailing whitespace
    s = s.strip()

    # Ignore empty input
    if not s:
        continue

    if s == 'ABORT':
        break

    #We only want a single leter, so discard anything after the first letter
    s = s[0]

    # Get matching cities
    matches = city_index.get(s)
    if matches:
        print(matches)
    else:
        print('Nothing matches')

试运行

A {'Aix en Provence'}
B {'Bordeaux'}
C {'Clermont Ferrand'}
D {'Saint Denis'}
F {'Clermont Ferrand'}
H {'Le Havre'}
L {'Le Mans', 'Limoges', 'Lyon', 'Le Havre'}
M {'Le Mans', 'Mont de Marsan', 'Marseille', 'Montpellier'}
N {'Pont Neuf', 'Nice', 'Nantes', 'Nîmes'}
P {'Pont Neuf', 'Aix en Provence', 'Paris'}
S {'Strasbourg', 'Saint Étienne', 'Saint Denis'}
T {'Toulon', 'Tours', 'Toulouse'}
d {'Mont de Marsan'}
e {'Aix en Provence'}
É {'Saint Étienne'}

Select cities by an initial letter, or ABORT to quit
? S
{'Strasbourg', 'Saint Étienne', 'Saint Denis'}
? T
{'Toulon', 'Tours', 'Toulouse'}
? A
{'Aix en Provence'}
? C
{'Clermont Ferrand'}
? K
Nothing matches
? d
{'Mont de Marsan'}
? F
{'Clermont Ferrand'}
? M
{'Le Mans', 'Mont de Marsan', 'Marseille', 'Montpellier'}
? E
Nothing matches
? É
{'Saint Étienne'}
?   Silly
{'Strasbourg', 'Saint Étienne', 'Saint Denis'}
? ABORT