Python - 如何为用户输入创建删除功能?

Python - How to create a delete function for user input?

我一直在尝试创建一个程序,允许用户查看文本文件的内容并删除部分或全部单个条目块。

下面是文本文件内容的示例:

Special Type A Sunflower
2016-10-12 18:10:40
Asteraceae
Ingredient in Sunflower Oil
Brought to North America by Europeans
Requires fertile and moist soil
Full sun

Pine Tree
2018-12-15 13:30:45
Pinaceae
Evergreen
Tall and long-lived
Temperate climate

Tropical Sealion
2019-01-20 12:10:05
Otariidae
Found in zoos
Likes fish
Likes balls
Likes zookeepers

Big Honey Badger
2015-06-06 10:10:25
Mustelidae
Eats anything
King of the desert

因此,条目块指的是没有水平线的所有行 space。

目前我的进度是:

import time
import os
global o
global dataset
global database
from datetime import datetime

MyFilePath = os.getcwd() 
ActualFile = "creatures.txt"
FinalFilePath = os.path.join(MyFilePath, ActualFile) 

def get_dataset():
    database = []
    shown_info = []
    with open(FinalFilePath, "r") as textfile:  
        sections = textfile.read().split("\n\n")
        for section in sections:                 
            lines = section.split("\n")      
            database.append({                
              "Name": lines[0],
              "Date": lines[1],              
              "Information": lines[2:]          
            })
    return database

def delete_creature():
    dataset = get_dataset()
    
    delete_question = str(input("Would you like to 1) delete a creature or 2) only some of its information from the dataset or 3) return to main page? Enter 1, 2 or 3: "))
    
    if delete_question == "1":
        delete_answer = str(input("Enter the name of the creature: "))
        for line in textfile:
            if delete_answer in line:
                line.clear()
            
    elif delete_question == "2":
        delete_answer = str(input("Enter the relevant information of the creature: "))
        for line in textfile:
            if delete_answer in line:
                line.clear()
        
    elif delete_question == "3":
        break
        
    else:
        raise ValueError
    except ValueError:
        print("\nPlease try again! Your entry is invalid!")
        
while True:
    try:
        option = str(input("\nGood day, This is a program to save and view creature details.\n" +
                       "1) View all creatures.\n" +
                       "2) Delete a creature.\n" +
                       "3) Close the program.\n" +
                       "Please select from the above options: "))
        
        if option == "1":
            view_all()
            
        elif option == "2":
            delete()
                
        elif option == "3":
            break
            
        else:
            print("\nPlease input one of the options 1, 2 or 3.")
        
    except:
        break

delete_function() 旨在通过以下方式删除生物:

  1. 名称,删除与名称关联的整个文本块
  2. 信息,只删除一行信息

不过,我似乎无法使 delete_creature() 函数起作用,而且我不确定如何让它起作用。

有人知道如何让它工作吗?

非常感谢!

您从部分中删除行的问题是您专门硬编码了哪一行代表什么。在您的案例中删除一个部分很容易,如果您不改变您的概念,删除一行将涉及将有问题的行设置为空或稍后设置为表示空字符串的某个字符。 这里的另一个问题是,您是否需要您的部分保持输入时的顺序,或者您可以让它们以其他顺序重新排序到文件中。

我要做的是将输入文件格式更改为例如INI 文件格式。然后您可以使用 configparser 模块以简单的方式解析和编辑它们。 INI 文件如下所示:

[plant1]
name="Some plant's English name"
species="The plant's Latin species part"
subspecies="The plant's subspecies in Latin ofcourse"
genus="etc."

[animal1]
# Same as above for the animal
# etc. etc. etc.

configparser.ConfigParser() 将允许您以字典方式加载它并编辑部分和值。您可以命名 animal1、plant1 的部分,或将它们用作其他名称,但我更喜欢将名称保留在值中,通常在 name 键下,然后使用 configparser 从名称创建一个普通字典,其中它的值是另一个包含的字典key-value 对,如本节中指定的那样。我在保存结果时反转了这个过程。手动或再次使用 configparser。

您可能考虑的另一种格式是 JSON,使用 json 模块。 使用其函数 dumps() 并正确设置分隔符和缩进,您将获得漂亮的 human-readable 和可编辑的输出格式。好的是你保存了你正在使用的数据结构,例如字典,然后你加载它,它在你保存它时返回,你不需要执行一些额外的东西来完成它,就像 configparser 一样。问题是,对于不习惯 JSON 构建的用户来说,INI 文件不会那么令人困惑,并且会导致更少的错误,而 JSON 必须严格格式化,打开和打开时的任何错误关闭范围或使用分隔符会导致整个事情无法正常工作或输入不正确。而且文件大的时候很容易出现这种情况。

这两种格式都允许用户在任何地方放置空行,并且不会改变文件的加载方式,而您的方法对空行的要求很严格。

如果您希望您的数据库只能由您的程序编辑,那么请使用 pickle 模块来完成它并避免混乱。

否则你可以:

def getdata (stringfromfile):
    end = {}
    l = [] # lines in a section
    for x in stringfromfile.strip().splitlines():
        x = x.strip()
        if not x: # New section encountered
            end[l[0].lower()] = l[1:]
            l = []
            continue
        end.append(x)
    end[l[0].lower()] = l[1:] # Add last section
    # Connect keys to numbers in the same dict(), so that users can choose by number too
    for n, key in enumerate(sorted(end)):
        end[n] = key
    return end

# You define some constants for which line is what in a dict():
values = {"species": 0, "subspecies": 1, "genus": 2}

# You load the file and parse the data
data = getdata(f.read())

def edit  (name_or_number, edit_what, new_value):
    if isinstance(name_or_number, int):
        key = data[name_or_number]
    else:
        key = name_or_number.lower().strip()
    if isinstance(edit_what, str):
        edit_what = values[edit_what.strip().lower()]
    data[key][edit_what] = new_value.strip()

def add (name, list_of_lines):
    n = len(data)/2 # Number for new entry for numeric getting
    name = name.strip().lower()
    data[name] = list_of_lines
    data[n] = name

def remove (name):
    name = name.lower().strip()
    del data[name]
    # Well, this part is bad and clumsy
    # It would make more sense to keep numeric mappings in separate list
    # which will do this automatically, especially if the database file is big-big-big...
    # But I started this way, so, keeping it simple and stupid, just remap everything after removing the item (inefficient as hell itself)
    for x in data.keys():
        if isinstance(x, int):
            del data[x]
    for n, key in enumerate(sorted(data)):
        data[n] = key

def getstring (d):
    # Serialize for saving
    end = []
    for l0, ls in d.items():
        if isinstance(l0, int):
            continue # Skip numeric mappings
        lines = l0+"\n"+"\n".join(ls)
        end.append(lines)
    return "\n\n".join(end)

我没有测试代码。可能有错误。

如果您不需要特定的行,您可以轻松修改我的代码以使用 list.index() 方法在行中搜索,或者在需要时使用数字作为行(如果它们存在)他们。要使用 configparser 这样做,请在以下部分中使用通用键:answer0、answer1...,或仅使用 0、1、2...,然后忽略它们并将答案作为列表或其他方式加载。如果您要使用 configparser 来处理该文件,您有时会在删除时得到 answer0、answer3...。

还有一个警告。如果你想保持输入文件给生物的顺序,使用 ordereddict 而不是普通字典。

此外,就地编辑打开的文件当然是可能的,但很复杂且不可取,所以最好不要这样做。加载并保存回来。在极少数情况下,您想直接更改文件。为此,您将使用 mmap 模块。只是不要!