如何让每个字符输入一次?

How to allow each character to be entered once?

我有一个加密代码,它由 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)

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

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

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

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

编辑:假设您不希望代码 运行 如果 encryption_code 无效,您可以使用此标志从用户在 运行 完成程序的其余部分之前。

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

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

要在用户每次按键时调用此函数,请设置条目小部件的 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)

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

有关条目验证的更详尽解释,请参阅 Whosebug 上的此答案: