Python 正则表达式:匹配(搜索)使用输入字符串和操作中的列表元素

问题描述 投票:0回答:1

作为 Python 文本游戏的一部分,我想使用正则表达式从用户输入字符串中的列表或字典中搜索元素,如果元素匹配,则处理各种操作。

我已经尝试了大约十几个不同版本的正则表达式代码,但没有一个能够准确地提供我正在寻找的结果。

我之前只在非常有限的(数据分析)环境中使用过正则表达式,而且我对其行为的理解很狭窄。 (我从一个简单的 split 方法开始,应用于用户输入字符串,该方法在有限的上下文中工作得很好,但是,因为 List 元素可以有不同的长度(例如,1 到 4 个单词),所以很快就变得不可行拆分而无需编写针对不同列表元素的十几个条件。)

用户输入的字符串将遵循非常可预测的模式,因此这似乎是一个相对直接的解决方案的问题。

输出/动作场景:

  1. 如果 Use 语句中调用的 [库存列表元素] 在库存列表中,并且是“可用”(参见:物品字典),则打印“您使用 [库存列表元素]”

  2. 如果 Use 语句中调用的 [Inventory List Element] 在 Inventory List 中,并且不是“可用”(如项目字典中所定义),则打印“没有发生任何您可以感知到的事情。”

  3. 如果使用语句中调用的[库存列表元素]不在库存列表中,则打印“该商品不在您的库存中。”

我遇到的问题(好吧,无论如何,其中之一)是正则表达式搜索迭代库存列表中的每个项目,并返回一个响应;如果我使用简单的 >> pass << to eliminate a response when no match is made, I can't call Scenario 3, which is that the Item called in the Use statement was not in the inventory.

例如,如果用户输入语句是“在骨架上使用粉红兔子”,并且“粉红兔子”不在库存中,则循环将返回到开头并询问用户他们想要什么操作采取。

我尝试使用 re.findall 语句来创建 re.search 响应列表,如果所有响应均为“无”,则运行场景 3,但随后我无法分解该列表以挑选出匹配的如果使用语句确实包含库存中的项目,则为项目。 (即使尝试调用场景 3,代码也变得不稳定,以返回“该物品不在您的库存中。”。)

我在下面想出了一个(非常)简单的正则表达式,它单独评估“已使用”的物品是否在库存中,并且作为单独的 for 循环,评估目标是否是合法目标。见下文。但是,我无法将第一个 for 循环中标识的项目传递到第二个(目标)for 循环,以创建一个连贯的语句,“您在 [匹配目标] 上使用了 [匹配项目]。” (Target for 循环获取库存列表中的下一个项目并将其插入,这或多或少是有意义的。)

如有任何建议,我们将不胜感激;每次我认为我有解决方案时,我都会遇到最后一个我无法解决的问题。

(模型) str = '在 [目标列表元素] 上使用 [库存列表元素]'

import re
    
inventory = ['Golden Cape', 'White Diamond Key', 'Carving Knife', 'Silver Long Sword', 'Citrine Key']
    
selected_action = 'use Pink Bunny on Black-Boned Skeleton'
    
def match(selected_action):
    for item in inventory:
        match = re.search(fr'use\s{item}', selected_action)
            if match:
                # print(match)
                # print(item)
                print(f'you use {item}')
            else:
                # pass
                print('no item')
    
    for target in targets_detail:
        match = re.search(fr'on\s{target}', selected_action)
            if match:
                # print(match)
                # print(target)
                print(f'you use {item} on {target}')
            else:
                # print('no target')
                pass
    
match(selected_action)


targets_detail = {
    'None':
        {
            'type': 'Enemy',
            'room': 'None',
            'available': 'No',
            'removed from room': 'True',
            'useable': 'No',
            'vulnerable to': 'None',
            'item descr':
                '''
        No item description.
                ''',
            'in-room descr':
                '''
        No other persons appear to be present.        
                ''',
            'creature death descr':
                '''
        No creature death description.
                ''',
            'player death descr':
                '''
        No Player death description.
                '''
        },
    'Frost Giant':
        {
            'type': 'Enemy',
            'room': 'Kitchen',
            'available': 'No',
            'removed from room': 'False',
            'useable': 'No',
            'vulnerable to': 'Lochaber Axe',
        },
    'Black-Boned Skeleton':
        {
            'type': 'Enemy',
            'room': 'North Parlor',
            'available': 'No',
            'removed from room': 'False',
            'useable': 'No',
            'vulnerable to': 'Silver Long Sword',
        },
    'Cabinet':
        {
            'type': 'Misc',
            'room': 'Library',
            'available': 'No',
            'removed from room': 'False',
            'useable': 'No',
            'vulnerable to': 'Silver Candelabra',
        }
}
python regex search
1个回答
0
投票

请注意,这是标记化用户输入的一般主题,并且相当复杂且充满危险和歧义!

也就是说,为了获得更好的系统,如果你没有太多的物品(比如几千个 - 我展示了一个 certesian 产品来进行每种组合,但你不太可能真的想要这个),我不会直接使用为此的正则表达式(尽管它们可能有助于提取和比较术语!),但请考虑各种技术,特别是

difflib.get_close_matches()
标准化输入数据

import difflib
import itertools
import re

modifier_1 = {
    "black",
    "carving",
    "citrine",
    "golden",
    "pink",
    "silver",
    "white",
}
modifier_2 = {
    "",  # nothing - caution lazy
    "boned",
    "long",
}
names = {
    "bunny",
    "cape",
    "key",
    "knife",
    "skeleton",
    "sword",
}

collection = set(map(
    " ".join,
    itertools.product(modifier_1, modifier_2, names)
))

def check_use(data):
    data = data.lower().strip()
    # check for no data
    A, B = re.match("^use (.*) on (.*)$", data).groups()
    try:
        A = get_close_matches(A, collection)[0]
        B = get_close_matches(B, collection)[0]
    except IndexError:  # didn't find and match
        return None     # warn the user about their input
    return A, B
>>> check_use("use Pink Bunny on Black-Boned Skeleton")
('pink  bunny', 'black boned skeleton')
>>> check_use("use White Key on golden long-sword")
('white  key', 'golden long sword')
© www.soinside.com 2019 - 2024. All rights reserved.