【问题标题】:Retrieving and checking a password in python with a csv file使用 csv 文件在 python 中检索和检查密码
【发布时间】:2015-02-18 15:59:52
【问题描述】:

我正在尝试编写一个要求输入电子邮件和密码(不是出于任何特定目的)的代码,并将它们与包含多行的 csv 文件进行检查。每行都包含一个电子邮件和密码以及一些虚构的客户详细信息。我正在尝试编写一个接受电子邮件地址和密码(5 - 12 个字符长)的代码,然后在文件中搜索包含电子邮件和密码的行并打印整行(包括客户详细信息)。到目前为止,这是我的代码(有些缩进在这里可能看起来有点奇怪,但实际上只是代码块缩进的结果):

import csv
import re
import sys

f = open('A453_datafile_4_Mat 4 Data File.csv', 'r').read()

print("Welcome to our website! To access your customer details, we first require you to sign in. ")
print("")
email = input ("Email address: ")
if re.match("\A(?P<name>[\w\-_]+)@(?P<domain>[\w\-_]+).(?P<toplevel>[\w]+)\Z",email,re.IGNORECASE):
print('')
else:
    email = input("Sorry, this isn't a valid email address! Try again: ")
    if re.match("\A(?P<name>[\w\-_]+)@(?P<domain>[\w\-_]+).(?P<toplevel>[\w]+)\Z",email,re.IGNORECASE):
        print('')
    else:
        print("You have entered your email incorrectly two times. The program will now terminate." )
    sys.exit() #ends program

password = input ("Password: ")
if re.match("\A(?P<name>[\w\-_]+)\Z",password,re.IGNORECASE): 
    print('')
else:
   password = input("Sorry, this isn't a valid password! Try again: ")
   if re.match("\A(?P<name>[\w\-_]+)\Z",password,re.IGNORECASE):
        print('')
   else:
        print("You have entered your password incorrectly two times. The program will now terminate." )
        sys.exit() #ends program


details = [line for line in f.split('\n') if email in line] and [line for line in f.split('\n') if password in line]

if details == []:
   print("Sorry, your email or password is invalid.")
else:
   print("Thank you! Here are your customer details: ")
   print("")
   details = str(details).strip('[]')
   print(details)

我在使用这条线时遇到了问题,因为“和”似乎无法按我的意愿工作:

details = [line for line in f.split('\n') if email in line] and [line for line in f.split('\n')

如果我故意输入错误的密码(例如字母“x”),并且它恰好存在于另一行,它会打印该行,尽管它不包含电子邮件地址。

这是一个例子:

欢迎访问我们的网站!要访问您的客户详细信息,我们首先要求您登录。

电子邮件地址:ojones@coldmail.net

密码:x

谢谢!以下是您的客户详细信息:

'miguel5@bluebell.net,happy3,Miguel,Santos,45 Vine Avenue,Oxford,OX7 3RF'

虽然它使用正确的密码:

欢迎访问我们的网站!要访问您的客户详细信息,我们首先要求您登录。

电子邮件地址:ojones@coldmail.net

密码:ocrabc

谢谢!以下是您的客户详细信息:

'ojones@coldmail.net,ocrabc,Oliver,Jones,53 Vale House,朴茨茅斯,P03 2TD'

还有这个正则表达式,因为我不知道如何将密码长度限制为 5 - 12 个字符(我是正则表达式的新手,还没有学会如何使用它):

if re.match("\A(?P<name>[\w\-_]+)\Z",password,re.IGNORECASE)

我怀疑修复此问题可能主要解决前一个问题(除非有人知道文件的内容),但如果可能的话,我们将不胜感激。

可能还有其他一些我没有意识到的问题,但据我所知,仅此而已。

我知道这个问题很长,所以感谢您抽出宝贵时间阅读它,任何答案将不胜感激!

【问题讨论】:

  • 呃——不要以纯文本形式存储密码...
  • 别介意我问,为什么没有数据库?
  • @Jesse W at Z - 它们不是真正的密码,所有信息都是为​​了这个程序的目的而编造的。
  • @StefanNch - 数据库?我需要一个吗?
  • 你必须为索尼工作。

标签: python regex email csv line


【解决方案1】:

问题很长,答案很简单。不要将布尔运算“和”用于列表连接。使用 + 它将产生正确的列表。 'and' 做什么 - 它将每个操作数转换为布尔值 True/False,如果两个列表都不为空 - 返回最后一个。否则它返回 [] (在你的情况下永远不会发生)。

【讨论】:

  • 谢谢!之前没用过 and 我觉得在这种情况下可能比 + 更合适,显然我下次应该都试试!
【解决方案2】:

您的代码当前正在执行的操作是对文件进行两次循环:每个 [line for line in f.split()] 都是一个单独的循环。第一个循环获取电子邮件匹配的行列表,第二个循环获取密码匹配的行列表。

然后您将使用“和”运算符组合两个列表。 Python 允许您这样做,如果两个列表都不为空,则结果将为 True,否则为 False。由于您试图将操作结果与 [] 进行比较,因此比较总是会失败。

您尝试做的正确版本是有一个循环并同时检查两个条件,Python 列表推导允许您这样做:

[line for line in f.split() if email in line and password in line]

但是,由于这是一个子字符串检查,当用户正确输入密码的一部分时,这将匹配,这通常不是您检查密码时想要的。相反,您应该检查整个字符串:

line.startswith(email + "," + password + ",")

【讨论】:

  • 谢谢,这真的很有帮助。我不确定如何检查整个字符串。
【解决方案3】:

这是一个在 CSV 文件中搜索特定字符串的简单实现:

f = open('A453_datafile_4_Mat 4 Data File.csv', 'r').read() 
rows = re.split('\n', f.decode())

for index, row in enumerate(rows):
    cells = row.split(',')
    if ('USER_EMAIL_HERE' in cells) and ('USER_PASSWORD_HERE' in cells):
        #Do stuff here

我还没有测试过,仅供参考。

【讨论】:

    【解决方案4】:

    这是一个清理后的版本:

    import csv
    from collections import namedtuple
    from itertools import repeat
    import re
    import sys
    
    EMAIL_REG    = re.compile("^([\w\-_]+@[\w\-_]+\.[\w]+)$", re.IGNORECASE)
    PASSWORD_REG = re.compile("^([\w\-_]{5,12})$", re.IGNORECASE)
    PASSWORD_CSV = 'A453_datafile_4_Mat 4 Data File.csv'
    
    # define a User type
    #   (the field names should match the columns from the .csv file)
    User = namedtuple("User", ["email", "password", "firstname", "lastname", "address", "city", "postalcode"])
    # prettier output
    User.__str__ = lambda self: "{} {}: {} ({} {}, {})".format(self.firstname, self.lastname, self.email, self.address, self.city, self.postalcode)
    
    def all_users_from_csv(fname, **kwargs):
        """
        Return an iterable of Users from the specified csv file
        """
        with open(fname) as in_file:
            for row in csv.reader(in_file, **kwargs):
                yield User(row)
    
    def match_user(users, email, password):
        """
        Return the first user in users who matches the specified email and password;
          on failure, return None
        """
        for user in users:
            if user.email == email and user.password == password:
                return user
        return None
    
    def input_match(prompt, reg, max_tries=None):
        """
        Prompt for input that matches reg;
          on success, return first match group
          on failure, try again (up to max_tries times, if specified)
          on max_tries failures, return None
        """
        if max_tries is None:
            # not specified - repeat forever
            tries = repeat(None)
        else:
            # repeat specified number of times
            tries = range(max_tries)
    
        for i in tries:
            s = input(prompt)
            m = reg.match(s)
            if m:
                return m.groups(0)
    
        # if max_tries exceeded
        return None
    
    def do_signin():
        email = input_match("Email address: ", EMAIL_REG, 2)
        if email is None:
            print("You did not enter a valid email address. Good-bye!")
            return None
    
        password = input_match("Password: ", PASSWORD_REG, 2)
        if email is None:
            print("You did not enter a valid password. Good-bye!")
            return None
    
        users = all_users_from_csv(PASSWORD_CSV)
        return match_user(users, email, password)
    
    def main():
        print("Welcome to our website! To access your customer details, we first require you to sign in.\n")
    
        user = do_signin()
        if user is None:
            print("Sorry, your email or password is invalid.")
        else:
            print("Thank you! Here are your customer details:\n")
            print(user)
    
    if __name__=="__main__":
        main()
    

    还有一些cmets:

    1. 请注意,每次要匹配用户时,都必须比较(最多).csv 文件中的每一行;这是缓慢而浪费的。几乎任何数据库都允许您对电子邮件和密码字段进行索引,从而提高效率。

    2. 我将代码拆分为单独的函数;每个功能都很简单,只有一个特定用途。命名常量、良好的函数名、文档字符串和 cmets - 它们都使您的程序更易于理解、测试和以后修改。

    【讨论】:

      猜你喜欢
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 2016-07-22
      • 1970-01-01
      • 2018-12-02
      相关资源
      最近更新 更多