【问题标题】:replace the nth character of a string (RegEx or not)替换字符串的第 n 个字符(RegEx 与否)
【发布时间】:2021-04-27 04:35:23
【问题描述】:

我正在尝试编写一个词汇游戏。首先声明,我是一个完全的菜鸟程序员!

我正在使用正则表达式来隐藏一个我必须猜测的单词。

chosen_word为例:

'TO CRANK (STH) UP'

使用 RegExs 我设法隐藏关键字,并且我有 hidden_​​word 如下:

TO _ _ _ _ _ (STH) _ _

使用 RegEx findall()filter() 方法,我得到一个 hidden_​​letters 列表:

['C', 'R', 'A', 'N', 'K', 'U', 'P']

这个想法是我们现在从这个列表中随机选择一个字母来显示给用户:

chosen_letter = random.choice(hidden_letters)

n = hidden_letters.index(chosen_letter) + 1

现在所选字母的 n 漂亮地映射到 hidden_​​word 中相应的下划线。例如,如果游戏随机选择了字母“R”,那么 n 将是“2”,并且在 hidden_​​word 中这个字母的位置是第二个下划线。

我现在被困在这个阶段。我想用 chosen_letter 替换 hidden_​​word 的第 n 个下划线。我正在考虑使用 .replace() 方法或 RegEx re.sub() 方法,但我不知道如何开始。

有人可以给我提示吗?

提前非常感谢!!

【问题讨论】:

  • 如果隐藏词中有重复的字母,期望的行为是什么?另外,在您的示例中,隐藏词是什么?
  • 隐藏词是'TO _ _ _ _ _ (STH) _ _ ',就是显示给用户的。是的,我已经考虑过重复字母的问题——虽然还没有解决哈哈,但期望的行为是它替换了第一次出现的重复字母,并且在后续迭代中不再考虑这个问题.
  • 也许一些具有所需行为的示例会有所帮助。它还可以帮助您描述在各种极端情况下所需的确切行为。
  • 您需要两个列表:一个带有完整的短语,一个带有下划线。当请求索引时,将第二个列表中的下划线替换为第一个列表中的值并输出给用户。

标签: python regex replace substring


【解决方案1】:

我会以不同的方式处理这个问题:

每个时间点的状态定义为:

  • 完整的短语(待猜),
  • 一组隐藏词,
  • 到目前为止猜到的字母(或将向用户显示)。

你可以用这三个量定义一个show()函数:

def show(phrase, hidden_words, letters_guessed):
    parts = [
        ''.join([
            c if c in letters_guessed else '-' for c in w
        ]) if w in hidden_words else w
        for w in phrase.split()
    ]
    return ' '.join(parts)

有了它,您可以编写测试,包括 doctest。这将使您的代码更易于记录、调试、测试和使用。

一些示例(可以作为文档测试包含在show 的文档字符串中):

phrase = 'TO PIPE (STH) UP AND PIPE DOWN'
hidden_words = {'PIPE', 'UP'}

>>> show(phrase, hidden_words, {})
'TO ---- (STH) -- AND ---- DOWN'

>>> show(phrase, hidden_words, set('I'))
'TO -I-- (STH) -- AND -I-- DOWN'

>>> show(phrase, hidden_words, set('PI'))
'TO PIP- (STH) -P AND PIP- DOWN'

【讨论】:

    【解决方案2】:

    鉴于您是新手,我想把我的帽子扔进去,不用正则表达式并尝试解释。也许只有在你完成后才能阅读。您的问题标题可以这样回答:

    def replace_nth_char(string, n, replacement):
        n -= 1
        l_string = list(string)
        l_string[n] = replacement
        return ''.join(l_string)
    

    它将字符串转换为可以用索引n 替换的字母列表,然后将其连接起来。

    我还尝试向您展示更多 python 选项。

    在管理状态时,您可能需要考虑using a class。它可以帮助您将所有功能和属性包装到一个有目的的对象中 - 玩您的词汇游戏。我建议调查他们。这是游戏中的一个:

    import random
    
    
    class VocabularyGame():
        def __init__(self, chosen_words, hidden_words):
            self.chosen_words = chosen_words
            self.hidden_words = hidden_words
            self.hidden_letters = list(set(''.join(words)))
            self.masked_sentence = self.mask_words(chosen_words, hidden_words)
            print(f"Game start: {self.masked_sentence}")
            
        def mask_words(self, sentence, masks):
            return ' '.join(['_'*len(w) if w in masks else w for w in sentence.split(' ')])
        
        def try_letter(self, letter=None):
            if letter is None:
                letter = random.choice(self.hidden_letters)
            self.masked_sentence = ''.join(
                [c if c== letter else m for m, c in zip(self.masked_sentence, self.chosen_words)]
            )
            self.hidden_letters = [l for l in self.hidden_letters if l != letter]
            print(f"Trying letter {letter}...\nRemaining letters: {self.masked_sentence}")
    

    __init__ 部分在我们创建新游戏实例时运行,并采用三个参数(self, chosen_words, hidden_words)。使用self 引用当前类实例(或游戏),我们可以使用它来设置和检索类的属性,在这种情况下,以记住我们的单词和句子。

        def __init__(self, chosen_words, hidden_words):
            self.chosen_words = chosen_words
            self.hidden_words = hidden_words
            self.hidden_letters = list(set(''.join(hidden_words)))
            self.masked_sentence = self.mask_words(chosen_words, hidden_words)
            print(f"Game start: {self.masked_sentence}")
    

    list(set(''.join(words))) 将隐藏单词中的所有唯一字母连接成一个字符串,using sets 将它们转换为唯一字母。我将其转换回列表以方便以后使用。

    然后我们应用一个函数来掩盖带有“_”的单词。

        def mask_words(self, sentence, masks):
            return ' '.join(['_'*len(w) if w in masks else w for w in sentence.split(' ')])
    

    这会遍历句子中的每个单词,如果单词存在于隐藏单词中,则将其替换为单词长度的“_”。然后它重新加入它。现在我们有了开始状态。

    最后要做的是尝试一个字母。我们通过定义一个方法(类上的函数)def try_letter(self, letter=None): 来做到这一点。如果没有提供字母,我们会从之前定义的唯一缺失字母中随机选择一个。 我们使用zip 一起检查原始句子中的每个字母和掩码句子中的每个字母,当原始字母是我们选择的字母时,我们替换掩码句子中的那个。

            self.masked_sentence = ''.join(
                [c if c==letter else m for m, c in zip(self.masked_sentence, self.chosen_words)]
            )
    

    然后从我们的隐藏字母列表中删除字母:

    self.hidden_letters = [l for l in self.hidden_letters if l != letter]

    最后,我们使用f-strings 打印出结果。 现在,我们可以玩游戏了!

    chosen_word = "TO CRANK (STH) UP"
    words = ['CRANK', 'UP']
    
    game = VocabularyGame(chosen_word, words)
    

    输出:Game start: TO _____ (STH) __

    尝试一个字母 7 次 for i in range(7): game.try_letter() 输出:

    Trying letter N...
    Remaining letters: TO ___N_ (STH) __
    Trying letter K...
    Remaining letters: TO ___NK (STH) __
    Trying letter R...
    Remaining letters: TO _R_NK (STH) __
    Trying letter P...
    Remaining letters: TO _R_NK (STH) _P
    Trying letter C...
    Remaining letters: TO CR_NK (STH) _P
    Trying letter U...
    Remaining letters: TO CR_NK (STH) UP
    Trying letter A...
    Remaining letters: TO CRANK (STH) UP
    

    【讨论】:

    • 非常感谢 chsws 的全面回复!我正在消化所有 Class 的东西,但与此同时,更基本的一点(您对 replace_nth_char() 方法的定义)......我为函数提供了一个值“n”,我已经计算出来了,但没有t 很好地映射到 [n] 索引。让我们考虑一下“APPLE”这个词,它全部隐藏为 (_ _ _ _ _ )。我选择显示 n=4 中的字母“L”。传递给函数的隐藏字符串,变成列表后,是['', ' ', '', ' ', '', ' ', ' ', ' ', '_', ' '],所以 l_string[4] 不是第四个下划线...
    • 嗨@XavierVillàAguilar,你必须提供一些代码让我评论。该函数工作正常:apple_masked = '_'*5 replace_nth_char(apple_masked,3,'L') 输出:'____L_' python 中的索引从 0 开始,因此第 4 个字符是位置 3。我修改了上面的函数。
    猜你喜欢
    • 1970-01-01
    • 2017-12-01
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 2015-10-24
    • 1970-01-01
    相关资源
    最近更新 更多