简体   繁体   中英

Python replace all characters in a string except for 3 characters with underscores

I'm working on a simple hangman app and I am trying to replace all the chars but three, in a word users have to guess, with underscores randomly.

So for example: America to A_M___C_

I have most of it down, but my code sometimes leaves more than 3 characters unconverted to underscores. Here is my code:

topics = {
    "movie": ["Star-Trek", "Shang-Chi"],
    "place": ["PARIS", "AMERICA", "ENGLAND"]
} 
topic = random.choice(["movie", "place"])
solution = random.choice(topics[topic])
question = ""
length = len(solution)
underscores = length - 3

for char in solution:
    for i in range(underscores):
        add = question + random.choice([char, "_"])
        question = question + add

Let's rehash your problem statement:

Given a string of unspecified length with more than three different characters, you want to keep three of these unique characters, and replace all the others.

Notice that the string could contain duplicates, so if your string is "abracadabra" and a is one of the letters you want to keep, that already gets you a__a_a_a__a .

import random


topics = {
    "movie": ["Star-Trek", "Shang-Chi"],
    "place": ["PARIS", "AMERICA", "ENGLAND"]
} 
topic = random.choice(["movie", "place"])
solution = random.choice(topics[topic])

characters = set(solution)
keep = random.sample(list(characters), 3)

question = solution
for char in characters.difference(keep):
    question = question.replace(char, '_')

set(solution) produces a set of the unique characters in the string, and random_sample(list(characters), 3) picks three of them (forcing the set back to a list is required to avoid a deprecation warning in Python >= 3.9). We then use the set.difference() to loop over the remaining unique characters, and replace all occurrences of them with underscores.

Your attempt doesn't normalize characters to upper or lower case; I would assume this is something you would actually want to do, but then probably normalize the questions to upper case already in the source. I'm leaving this as an excercise; this code simply regards a and A as different characters.

You have a few problems in your code. First of all the inner loop will restart for every character but that's not what you want. You want to put x underscores. Secondly, you only need to add your random choice, and not the while question. So, below a working program:

# get len(solution) - 3 unique numbers 
indices = random.sample(range(len(solution)), len(solution) - 3) 
question = list(solution) # convert to a list so we can index
for i in indices:
    question[i] = "_" # change them to underscores

question = "".join(question) # convert to list to a string

The reasen your solution (and my previous solution) don't work is because the number of not underscores isn't limited. So you could keep a counter with the number of not underscores, and when that's equal to 3, only replace characters by underscores like this, but keep in mind you would still need to track the number of underscores. So this solution is better.

Here is one function that takes in a string and optional number to save letters, so 3 will save 3 letters, 5 will save 5 letters. There is no error check to see if save_letters is larger than the word and so forth. The code is supposed to show you exactly what is happening, not to be a clever one liner.

import random 
def change_word(word, save_letters = 3):
    length = len(word)
    randies = []
    ret = ""
    while len(randies) < save_letters:
        x = random.randint(0,length - 1)
        if not x in randies:
            randies.append(x)
    for i in range(0, len(word)):
        if i in randies:
            ret += word[i]
            continue
        ret += "_"

    return ret

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM