首页 > 解决方案 > 如何使用部分字符串匹配搜索字典列表并且不区分大小写,然后显示结果?

问题描述

我正在创建通过导入 csv 文件创建的两个列表的字典。这两个列表中的每一个都包含多个字典列表,每个列表有 8 个键:值对。每个字典都包含有关一个特定项目的信息。其中一个列表是有关多本书的信息;另一个是有关多部电影的信息。

我需要通过允许用户输入查询字符串来查询图书列表,该查询字符串将用于搜索图书列表中的多个字段。搜索需要执行部分字符串匹配并且不区分大小写。应显示所有匹配书籍的所有详细信息,而不重复任何条目。

如果它与查询字符串匹配,如何搜索列表并打印整个字典?

# Note to self: book_collection is a list
# ORDER OF INFO in book_collection: title, author, publisher, pages, year, copies, available, ID
def query_book_collection(book_collection):
    # check to see if the string is in the dictionary--partial string matching and case insensitive
    query_string = input("Enter a query string to use for the search: ")

   if query_string.lower() in book_collection:
        print(book_collection)
   else:
        print("Sorry, that search returned no results.")

以我现在编码的方式,我希望它只匹配完整的直接匹配(不是部分字符串匹配),然后打印完整的 book_collection;但是,它只会打印“抱歉,该搜索未返回任何结果”。

编辑:我已将 query_string.lower 更新为 query_string.lower()。

书籍词典有22个列表,我相信每个列表都是一本字典。一个列表(来自调试器)如下所示,例如:

:{“标题”:“我有史以来最好的书”,“作者”:“约瑟夫考德威尔”,“出版商”:“FPG Publishing”,“页数”:“317”,“年份”:“2014”,“副本” :3,“可用”:3,“ID”:17001}

目标是能够搜索任何短语,如果该短语出现在上面的字典中,则将打印整个字典。

对于那些询问的人,这里有更多代码可以提供更大的上下文。我最初分享的代码就在长打印菜单的下方:

# each subset of the collection.
def load_collections():
    # Load the two collections.
    book_collection, max_book_id = load_collection("books.csv")
    movie_collection, max_movie_id = load_collection("movies.csv")

    # Check for error.
    if book_collection is None or movie_collection is None:
        return None, None

    # Return the composite dictionary.
    return {"books": book_collection, "movies": movie_collection}, max(max_book_id, max_movie_id)


# Loads a single collection and returns the data as a list.  Upon error, None is returned.
def load_collection(file_name):
    max_id = -1
    try:
        # Create an empty collection.
        collection = []

        # Open the file and read the field names
        collection_file = open(file_name, "r")
        field_names = collection_file.readline().rstrip().split(",")

        # Read the remaining lines, splitting on commas, and creating dictionaries (one for each item)
        for item in collection_file:
            field_values = item.rstrip().split(",")
            collection_item = {}
            for index in range(len(field_values)):
                if (field_names[index] == "Available") or (field_names[index] == "Copies") or (field_names[index] == "ID"):
                    collection_item[field_names[index]] = int(field_values[index])
                else:
                    collection_item[field_names[index]] = field_values[index]
            # Add the full item to the collection.
            collection.append(collection_item)
            # Update the max ID value
            max_id = max(max_id, collection_item["ID"])

        # Close the file now that we are done reading all of the lines.
        collection_file.close()

    # Catch IO Errors, with the File Not Found error the primary possible problem to detect.
    except FileNotFoundError:
        print("File not found when attempting to read", file_name)
        return None
    except IOError:
        print("Error in data file when reading", file_name)
        return None

    # Return the collection.
    return collection, max_id


# Display the menu of commands and get user's selection.  Returns a string with the user's requested command.
# No validation is performed.
def prompt_user_with_menu():
    print("\n\n********** Welcome to the Collection Manager. **********")
    print("COMMAND         FUNCTION")
    print("  ci         Check in an item")
    print("  co         Check out an item")
    print("  ab         Add a new book")
    print("  am         Add a new movie")
    print("  db         Display books")
    print("  dm         Display movies")
    print("  qb         Query for books")
    print("  qm         Query for movies")
    print("  x          Exit")
    return input("Please enter a command to proceed: ")

# Create the query function. Prompts user to enter query string for a book and
# displays ALL results--partial string matching and case insensitive. Note to self: book_collection is a list
# ORDER OF INFO in book_collection: title, author, publisher, pages, year, copies, available, ID
def query_book_collection(book_collection):
    # check to see if the string is in the dictionary--partial string matching and case insensitive
    query_string = input("Enter a query string to use for the search: ")

    if query_string.lower() in book_collection:
        print(book_collection)
    else:
        print("Sorry, that search returned no results.")

def query_movie_collection():
    pass

def check_out():
    pass

def check_in():
    pass

def get_item_ID():
    pass

def display_collection():
    pass

def add_book():
    pass

def add_movie():
    pass


# This is the main program function.  It runs the main loop which prompts the user and performs the requested actions.
def main():
    # Load the collections, and check for an error.
    library_collections, max_existing_id = load_collections()

    if library_collections is None:
        print("The collections could not be loaded. Exiting.")
        return
    print("The collections have loaded successfully.")

    # Display the error and get the operation code entered by the user.  We perform this continuously until the
    # user enters "x" to exit the program.  Calls the appropriate function that corresponds to the requested operation.
    operation = prompt_user_with_menu()
    while operation != "x":
         if operation == "ci":
             check_in(library_collections)
         elif operation == "co":
             check_out(library_collections)
         elif operation == "ab":
             max_existing_id = add_book(library_collections["books"], max_existing_id)
         elif operation == "am":
             max_existing_id = add_movie(library_collections["movies"], max_existing_id)
         elif operation == "db":
             display_collection(library_collections["books"])
         elif operation == "dm":
             display_collection(library_collections["movies"])
         elif operation == "qb":
             query_book_collection(library_collections["books"])
         elif operation == "qm":
             query_movie_collection(library_collections["movies"])
         else:
             print("Unknown command.  Please try again.")

    operation = prompt_user_with_menu()

# Start the program.
main()

标签: pythonpython-3.x

解决方案


在使用运算符之前,您可以将集合中的所有值连接在一起in

def query_book_collection(book_collection):
    query_string = input("Enter a query string to use for the search: ")
    collection_string = ",".join(map(str, book_collection.values())).lower()

    if query_string.lower() in collection_string:
        print(book_collection)
    else:
        print("Sorry, that search returned no results.")

book_collection但更有效的方法应该是添加一个新属性,当您在load_collection函数中加载集合时,它将所有要查询的值连接起来。喜欢(使用 python 内置csv模块读取 csv 文件):

def load_collection(file_name):
    try:
        with open(file_name, "r") as f:
            reader = csv.DictReader(f)
            collection = []
            max_id = -1

            for item in reader:
                # add a field for querying
                item["_fulltext"] = ",".join(item.values())

                # casting type
                item["Available"] = int(item["Available"])
                item["Copies"] = int(item["Copies"])
                item["ID"] = int(item["ID"])

                collection.append(item)
                max_id = max(max_id, item["ID"])

            return collection, max_id

    except FileNotFoundError:
        print("File not found when attempting to read", file_name)
        return None, None
    except IOError:
        print("Error in data file when reading", file_name)
        return None, None

然后,您的查询功能将是:

def query_book_collection(book_collection):
    query_string = input("Enter a query string to use for the search: ")

    if query_string.lower() in book_collection["_fulltext"]:
        print(book_collection)
    else:
        print("Sorry, that search returned no results.")

推荐阅读