从已知列表中,找出由已知字母组成的单词的方法是什么?

3

为了背景,这是一个有关宠物小精灵的问答机器人,我想尝试制作一个,但我的代码只适用于列表中的第一个单词(简单地说,这是从Bulbasaur开始的所有宠物小精灵的列表)。用户以下划线填空的格式输入已知字母和已知字母的位置(例如Bulbasaur可以是'_ _ l _ a s a _ _',没有空格)。用户还会输入已知字母数,供程序稍后使用。它读取列表,将其放入数组中,然后提取与输入单词长度相匹配的所有名称。然后开始比较每个字母和每个输入的字母以查找匹配项,如果匹配的字母(数量)等于给定的输入数字,则显示“the pokemon is:”和宠物小精灵名称。问题在于它仅适用于一个宠物小精灵,而其他宠物小精灵似乎无法工作。我将在下面发布代码,并希望得到任何帮助 :)

此外,如果需要列表,我可以以某种方式添加(超过500行)


poke = input("Letters and spaces given: ")

pokelen = input("Number of Letters given:")
print(pokelen)
pokelen = int(pokelen)

############################################
fid = open('pokemon.txt','r')
f = fid.readlines()
g = []
for i in f:
    i = i.replace('\n', '')
    g.append(i)
fid.close()

candidates = []
ticker = 0
while ticker != len(g):
    if len(g[ticker]) == len(poke):
        candidates.append(g[ticker])
    ticker +=1
print(candidates)
############################################
start = []
end = []
ticker1 = 0
ticker2 = 0
done = 0
while done == 0:
    while ticker1 != len(candidates):
        if done == 1:
            break
        word = candidates[ticker1]
        tick = 0
        length = len(word)
        a = 0       
        
        for i in word:
            start.append(i)
            tick += 1
        
        tick = 0
        for i in poke:
            end.append(i)
            tick += 1

        while length != ticker2:
            if start[ticker2] == end[ticker2]:
                a += 1
    
            ticker2 += 1

        if a == pokelen:
            print("The Pokemon is:",word)
            break
        ticker1 += 1
    done = 1
    print(done)
    print(a)
############################################

5
将用户的输入转换为正则表达式。例如:^..l.asa..$ - Barmar
1
当你最终学会了Python编程,相比于你现在所拥有的这段类C语言代码,你会为其简洁和简短而感到高兴。 - RufusVS
3个回答

2
如果您不想使用正则表达式,也可以通过比较字符串来完成!首先,让我们定义一个执行此操作的函数:
def is_match(pokemon: str, pattern: str) -> bool :
    return len(pokemon) == len(pattern) and \
           all(x == y for x, y in zip(pokemon, pattern) if y != "_")

这个函数对两个条件执行and操作:

  • 检查两个字符串的长度是否相同
  • zippokemonpattern字符串,并逐个字符迭代它们,检查所有字母对是否相等。如果字符串很大,这可能是一项昂贵的操作。

返回值是这两个条件的and。Python的短路逻辑确保仅在必要时(如果两个字符串的长度不相等,则没有必要尝试匹配模式)才执行可能昂贵的操作。

假设我们已经有了Pokemon列表和模式字符串:

all_pokemon = ["Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard", "Squirtle", "Wartortle", "Blastoise", "Caterpie", "Metapod", "Butterfree"] # and so on...

pattern = "__l_asa__".lower()

我们只需要遍历我们的 Pokemon 列表,在每一个 Pokemon 上运行 is_match 函数,并仅选择那些 is_match 为 true 的 Pokemon。

pokemon = []
for p in all_pokemon:
    if is_match(p.lower(), pattern):
        pokemon.append(p)
print(pokemon) # Output: ['Bulbasaur']

或者,可以使用列表推导式:

pokemon = [p for p in all_pokemon if is_match(p.lower(), pattern)]
print(pokemon) # Output: ['Bulbasaur']

如果您尝试匹配适用于多个宠物小精灵的模式,那也很不错!

pattern = "ch_rm_____"
pokemon = [p for p in all_pokemon if is_match(p.lower(), pattern)]
print(pokemon) # Output: ['Charmander', 'Charmeleon']

首先,感谢您的回答 :) - Dusty
这似乎做到了我想要的,并且代码量少了很多。就像我在Jon的回答上面评论的那样,我是一个初学者,其中一些函数我之前不知道存在(或者如何使用)。再次感谢Pranav! - Dusty
1
@Dusty 很高兴能帮忙!我添加了循环方式来选择符合模式的宝可梦,然后再使用列表推导式。列表推导式本质上是一种简洁地编写完整循环的语法糖。如果有不清楚的地方,请随时问我。 - Pranav Hosangadi

1
我不确定while循环中的代码试图做什么。我认为您正在尝试将输入与潜在的神奇宝贝进行匹配。正如@RufusVS和@Barmar建议的那样,可能有一种方法可以在不使用while循环中的细节的情况下实现您要查找的内容。
最终,您是否会尝试制作一个“猜单词游戏”?
import re

############################################
## load names of all pokemon
############################################
#with open('pokemon.txt','r') as fid:
#    all_pokemon = [p_name.strip() for p_name in fid.readlines()]
all_pokemon = ["bulbasaur", "charmander", "eevee", "pikachu", "squirtle"]
############################################

############################################
# ask for a name to try to match
############################################
your_pokemon = input("Letters and spaces given (e.g. pik_chu): ").lower()
your_pokemon_re = re.compile("^%s$" % your_pokemon.replace("_", "."))
############################################

############################################
# from all_pokemon find potential matches
############################################
matches = [pokemon for pokemon in all_pokemon if re.match(your_pokemon_re, pokemon)]
############################################

############################################
# See if we can guess
############################################
for match in matches:
    if input("Is your pokemon %s? " % match).lower() in ("y", "yes"):
        print(":-)")
        break
else:
    print("I give up. I don't seem to know your pokemon")
############################################

如果您想逐个字符比较字符串(我认为这是您的意图),那么这里有一种修改方法可以实现:

############################################
## load names of all pokemon
############################################
#with open('pokemon.txt','r') as fid:
#    all_pokemon = [p_name.strip() for p_name in fid.readlines()]
all_pokemon = ["bulbasaur", "charmander", "eevee", "pikachu", "squirtle"]
############################################

############################################
# ask for a name to try to match
############################################
your_pokemon = input("Letters and spaces given (e.g. pik_chu): ").lower()
############################################

############################################
# Alternate (slight more traditional) way to find matches
# this compares character by character similar to what you did
############################################
# will ensure same length strings later
candidates = [pokemon for pokemon in all_pokemon if len(your_pokemon) == len(pokemon)]
matches = []
for pokemon in candidates:
    for index, character in enumerate(pokemon):
        if your_pokemon[index] not in (character, "_"):
            ## this character is not a match not a "_" so break
            ## if there is no break, a for loop does it's "else"
            break
    else:
        matches.append(pokemon)
############################################

############################################
# See if we can guess
############################################
for match in matches:
    if input("Is your pokemon %s? " % match).lower() in ("y", "yes"):
        print(":-)")
        break
else:
    print("I give up. I don't seem to know your pokemon")
############################################

首先我要道歉,我是个相对业余的程序员,有时我的代码可能不是很流畅 :) 但是,关于循环的过程如下:检查循环结束的条件是否适用 >> 定义必要的变量 >> 创建两个数组,一个是来自单词库的测试单词,另一个是输入的单词 >> 检查数组中每个元素('start' 中的第一个和 'end' 中的第一个)是否相等,如果相等,则将 'a' 加一 >> 如果 'a' 变量等于所需变量,则完成并显示 Pokemon。 - Dusty

0
我们在 Discord 机器人的“钓鱼” (类似hangman的游戏) 模块中实现了类似于这样的功能。我可能对你想要的东西有所误解,但我认为至少接近了。
我们定义了一个函数来分散这些名字。
def scatter(iterable):
    new_list = []
    for i in iterable:
        if random.randint(1, 2) == 1 and new_list.count("_") <= len(iterable) // 2:
            new_list.append("_")
        else:
            new_list.append(i)

    return "".join(new_list)

并且稍后使用它来调用它并等待它们的响应。

pkid = (await ctx.bot.db[1].forms.find_one({"identifier": poke.lower()}))[
        "pokemon_id"
    ]
    name = poke
    threshold = 5000

    inventory = details["cast_inv"]
    threshold = round(
        threshold - threshold * (inventory.get("shiny-multiplier", 0) / 100)
    )
    shiny = random.choice([False for i in range(threshold)] + [True])
    exp_gain = [
        t["price"] for t in SHOP if t["item"] == rod.lower().replace(" ", "-")
    ][0] / 1000
    exp_gain += exp_gain * level / 2
    base_time = random.randint(3, 7)
    if rod.lower() == "good-rod":
        rod_bonus = random.randint(1, 1)
        final_time = base_time + rod_bonus
        await asyncio.sleep(final_time)
    elif rod.lower() == "great-rod":
        rod_bonus = random.randint(1, 2)
        final_time = base_time + rod_bonus
        await asyncio.sleep(final_time)
    elif rod.lower() == "super-rod":
        rod_bonus = random.randint(1, 3)
        final_time = base_time + rod_bonus
        await asyncio.sleep(final_time)
    elif rod.lower() == "ultra-rod":
        rod_bonus = random.randint(2, 5)
        final_time = base_time + rod_bonus
        await asyncio.sleep(final_time)
    else:
        rod_bonus = random.randint(0, 1)
        final_time = base_time + rod_bonus
        await asyncio.sleep(final_time)
    
    scattered_name = scatter(name)
    e = discord.Embed(title=f"You fished up a... ```{scattered_name}```")
    e.set_footer(text=f"You have 10 Seconds to guess the Pokemon's name to catch it!\n")
    try:
        await embed.edit(embed=e)
    except discord.NotFound:
        await ctx.send(embed=e)

    def check(m):
        return (
            m.author == ctx.author
            and poke.lower() in m.content.lower().replace(" ", "-")
        )

    try:
        await ctx.bot.wait_for("message", check=check, timeout=15)
    except asyncio.TimeoutError:
        await ctx.send(f"TIME'S UP!\nUnfortunately the {poke} got away...")
        return

    pokedata = await ctx.bot.commondb.create_poke(
        ctx.bot, ctx.author.id, poke, shiny=shiny
    )
    ivpercent = round((pokedata.iv_sum / 186) * 100, 2)

您可以在我们的开源代码库中找到我们的“fishing cog”,以获取我们所做的完整“想法”,希望它能有所帮助。在GitHub上 /skylarr1227/dittobot-open


1
目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关编写良好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接