【问题标题】:How to allow each character to be entered once?如何让每个字符输入一次?
【发布时间】:2015-11-15 19:50:58
【问题描述】:

我有一个由 26 个字母组成的加密代码,以及一个允许用户根据需要更改它的选项。在多次尝试我的程序后,我遇到了一个错误,一个合乎逻辑的错误。用户可以更改代码,但也可以输入相同的字符 26 次或至少 1 个字符以上,这可能会破坏我的整个程序。有没有办法只允许用户只输入每个字母一次?到目前为止,这是我所拥有的:

import tkinter 

letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 

encryption_code = 'LFWOAYUISVKMNXPBDCRJTQEGHZ'

letters += letters.lower()
encryption_code += encryption_code.lower() 

window = tkinter.Tk()

encrypt_entry = tkinter.Entry(window)
encrypt_entry.pack()


def code_change(event):
    global encrypt_entry
    global encryption_code

    encryptget = encrypt_entry.get()

    if len(encryptget) == 26:
        print("You have changed the encryption code")
        encryption_code = encryptget
        encryption_code += encryption_code.lower()
        enc = dict(zip(letters, encryption_code)) 
        dec = dict(zip(encryption_code, letters))

    elif len(encryptget) < 26 or len(encryptget) > 26:
        print("Please enter 26 characters")
        encrypt_entry.delete(0, tkinter.END) 

window.bind('<Return>', code_change)

编辑 我尝试了以下方法,但现在如果我尝试输入字母表或encryption_codeelif 语句什么也不做。

import tkinter 

letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 

encryption_code = 'LFWOAYUISVKMNXPBDCRJTQEGHZ'

letters += letters.lower()
encryption_code += encryption_code.lower() 

window = tkinter.Tk()

encrypt_entry = tkinter.Entry(window)
encrypt_entry.pack()


def code_change(event):
    global encrypt_entry
    global encryption_code

    encryptget = encrypt_entry.get()

    if len(set(encryptget)) == 26 and encryptget != encryption_code and encryptget != letters:
        print("You have changed the encryption code")
        encryption_code = encryptget
        encryption_code += encryption_code.lower()
        enc = dict(zip(letters, encryption_code)) 
        dec = dict(zip(encryption_code, letters))

    elif len(set(encryptget)) != 26 and encryptget == encryption_code and encryptget == letters:
        print("Please enter each character exactly once")
        encrypt_entry.delete(0, tkinter.END)        

window.bind('<Return>', code_change)

【问题讨论】:

  • 如果你想让所有26个字符都是唯一的,那么len(set(encryptget)) == 26会发现; len(set('abc')) == 3len(set('aaa')) == 1.
  • 那么仅仅使用set()函数,它就允许26个唯一字符吗?另外,我不希望用户只能输入字母表——这会破坏加密部分——我已经对其进行了排序。
  • 一个集合只能包含unique元素,所以如果字符串有26个字符但有一个字符重复,那么集合会更短。
  • 我已经尝试了您的建议,当我输入字母表或加密代码时,elif 语句似乎不起作用。
  • elif 中你需要or 代替and。但你不需要elif 你可以使用else:

标签: python tkinter get tkinter-entry


【解决方案1】:

Tkinter 有一个专门用于这种验证的功能。您可以让它为每次插入调用一个函数,并且该函数可以根据您想要的任何标准接受或拒绝该插入。

在您的情况下,标准是“无重复字符”。一种简单的确定方法是将字符串转换为集合(根据定义,集合没有重复项),然后将集合的长度与字符串的长度进行比较。

要在用户每次按键时调用此函数,请设置条目小部件的validatevalidatecommand 选项。有一个额外的步骤,你必须注册命令,它告诉 tkinter 你希望你的命令接收几个特殊参数中的哪一个。

解决方案如下所示:

# Define a command to be run whenever the user edits the entry
# N.B. d will be "1" for an insert, "0" for delete, and "-1"
# for anything else. P will be the value of the entry if this
# edit is allowed.
#
# Note: this function must always return either True or False
def encryption_validation(d, P):
    if d == "1":   # ie: an insert
        unique_chars = set(P)
        if len(P) > len(unique_chars):
            return False
    return True

# register the command with tkinter
vcmd = (window.register(encryption_validation), '%d', '%P')

# configure the entry widget to use this command
encrypt_entry.configure(validate="key", validatecommand=vcmd)

使用上述方法,用户将不可能输入任何字符两次。请注意,此解决方案还可以防止用户粘贴具有重复字符的字符串。

有关条目验证的更详尽说明,请参阅 stackoverflow 上的此答案:https://stackoverflow.com/a/4140988/7432

【讨论】:

  • 谢谢,有没有办法也可以将其限制为仅大写字母?
  • @Inkblot:是的。你可以在里面放任何你想要的支票。
【解决方案2】:

如果我弄错了,请纠正我,但听起来您只是想确保用户为代码输入的字符串不包含任何重复项?

我个人不了解验证命令,但我认为这可以实现您的目标:

def IsCodeValid(encryption_code):
    c = [0]*26

    pos = 0
    for i in range(len(encryption_code)):
        pos = ord(encryption_code[i])-ord('A') #find placement relative to A in unicode
        c[pos] = c[pos] + 1 #increment counter for that letter

    j = 0
    ValidCode = True
    while j<26 and ValidCode:
        if c[j]>1: #check to see if any letter occurred more than once
            ValidCode = False
        else:
            j += 1

    return ValidCode

请注意,这也要求所有字母都大写。但是您可以通过在接受数据之前对其进行规范化来解决此问题。或者,您可以使检查大小写的逻辑复杂化。

编辑:这是假设如果加密代码无效,您不希望代码运行,您可以在运行程序的其余部分之前使用此标志向用户请求新的加密代码。

【讨论】:

  • 我已经试过你上面的代码了,有没有办法使用打印语句检查更改是否成功?
  • @InkBlot print ValidCode 会做到这一点。如果它返回 false 则不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
相关资源
最近更新 更多