0

The problem

I have a haystack:

source = '''    "El Niño" "Hi there! How was class?"

    "Me" "Good..."

    "I can't bring myself to admit that it all went in one ear and out the other."
    
    "But the part of the lesson about writing your own résumé was really interesting!"

    "Me" "Are you going home now? Wanna walk back with me?"

    "El Niño" "Sure!"'''

I have a mask:

out_table = '→☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔'

And I have a token -- (single space).

All their elements are strings (class of <str>).

I need a function that will:

  1. Iterate through haystack (source)
  2. Replace each occurrence of token ( ) with a single character randomly picked from the mask
  3. Will print resulting new haystack after the replacement process

Finally, I need a similar method that will revert the above process, so it will replace each occurrence (every character) of the →☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔ list into (space).

Expected result

An example (can vary -- randomness) example result is (just a printout):

↔◘↔▬"El→Niño"↓"Hi∟there!↓How↨was↨class?"

↔◘↔▬"Me"↓"Good..."

♥♦♣♠"I↓can't↨bring§myself↓to∟admit↓that↓it↓all↓went↓in↓one§ear↓and↓out§the↓other."

↔◘↔▬"But☻the☻part☻of↓the→lesson∟about↓writing↓own↓résumé§was§really→interesting!"

↔◘↔▬"Me"↓"Are↓you☻going↓home§now?→Wanna↓walk∟back↓with↓me?"

♥♦♣♠"El↓Niño"→"Sure!"

Assumptions:

  • Every space must be replaced in the haystack
  • Not every character out of mask must be used

So, I the most "randomly border" scenario all spaces will be replaced with the same character. Which isn't a problem at all as long as the whole process is reversible back to the original haystack (source).

My research and solution attempt

Since this is my first Python code, I have browsed a number of Python and non-Python related questions here and in the net and I have come with the following idea:

import random 
def swap_charcter(message, character, mask):
    the_list = list(message)
    for i in random.sample(range(len(the_list)), len(list(mask))):
        the_list[i] = random.choice(mask)
    return message.join(the_list)
    
# print(swap_charcter('tested', 'e', '!#'))
print(swap_charcter('tested', 'e','→☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔'))

But... I must be doing something wrong, because each time I run this (or many, many other) piece of code with just a space as an argument, I am getting the Sample larger than population or is negative error.

Can someone help here a little bit? Thank you.

EDIT: I have replaced list(character)list(message), as suggested in the comments.

6
  • 3
    h is larger than n, but you're saying to take len(h)-many items from n (or rather, a range the same length as n) with the call to sample. I think you have those lists backwards. Commented May 22, 2023 at 1:16
  • As I said, I am completely new to Python and I am completely loosing context here on what changes what. If you could take a look at the list line of the presented code then it should be pretty self-explanatory -- I want to swap in tested all e occurrences with a random character from →☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔. It would be great if last list would be used entirely, i.e. both e-s in source string should be replaced with a random character and result in for example: t§st→d. Commented May 22, 2023 at 1:23
  • 1
    s is the text that contains letters to be replaced, yes? Then it seems to me the first line of code should be list(s), not list(n)... Commented May 22, 2023 at 2:35
  • The function never refers to s, except for the last line return s.join(the_list), which is ... bonkers. Do you know how join() works? Commented May 22, 2023 at 2:48
  • I think it would help if you defined what each of your inputs is meant to be on your function. Maybe use names with meaning like string mask character. Commented May 22, 2023 at 2:57

2 Answers 2

2

Use a re.sub (regular expression substitution) to change all spaces to a random.choice from your out_table.

To restore, use str.translate and str.maketrans to translate all characters from out_table to spaces.

Example:

import re
import random

source = '''    "El Niño" "Hi there! How was class?"

    "Me" "Good..."

    "I can't bring myself to admit that it all went in one ear and out the other."
    
    "But the part of the lesson about writing your own résumé was really interesting!"

    "Me" "Are you going home now? Wanna walk back with me?"

    "El Niño" "Sure!"'''

out_table = '→☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔'

result = re.sub(' ', lambda m: random.choice(out_table), source)
print(result)

original = result.translate(str.maketrans(out_table, ' ' * len(out_table)))
print(original)

Output:

↨◘◘↑"El▬Niño"○"Hi∟there!→How♦was◘class?"

☻↔•☺"Me"§"Good..."

↓↨•∟"I↓can't∟bring☺myself∟to♥admit▬that§it▬all☻went↔in¶one○ear♦and•out☻the←other."
←♦•○
♣→♥↓"But♣the☺part♦of◘the↑lesson○about↑writing▬your♠own○résumé↨was∟really♦interesting!"

↨∟♠↑"Me"←"Are→you¶going←home○now?→Wanna☺walk♣back¶with◘me?"

◘←☺○"El↨Niño"§"Sure!"
    "El Niño" "Hi there! How was class?"

    "Me" "Good..."

    "I can't bring myself to admit that it all went in one ear and out the other."
    
    "But the part of the lesson about writing your own résumé was really interesting!"

    "Me" "Are you going home now? Wanna walk back with me?"

    "El Niño" "Sure!"
Sign up to request clarification or add additional context in comments.

Comments

1

A quick example:

import random 

mask = '→☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔'
original = 'The quick fox jumps over the lazy dog'

pieces = original.split(' ')
filled = [piece+random.choice(mask) for piece in pieces]
result = ''.join(filled)
result = result[0:-1]

print(result)

Result:
The♥quick○fox∟jumps•over↨the∟lazy♠dog

This method takes your string and:

  1. breaks it apart into all the slices (pieces) that don't have spaces (split),
  2. uses list comprehension to add on a random character to the end of each piece,
  3. joins them all back together (join),
  4. and finally takes off the one extra mask character at the end by slicing the resultant string (result[0:-1])

This solution uses the fact that strings are themselves iterables:

from collections.abc import Iterable
isinstance('hello', Iterable)

Result: True

You don't need to convert strings to lists to pick out individual characters or to get their length; you can do this directly.

Putting that together in a function and letting you specify the character to replace as a bonus, you get:

import random

def swap_characters(string, character, mask):
    '''Replace all instances of a character from a string with a random sample from mask

    Parameters
    ----------
    string : str
        The string to be modified
    character : str
        The character to be replaced
    mask : str
        The string of characters from which to sample

    Returns
    -------
    str
        The modified string
    '''

    pieces = string.split(character)
    filled = [piece+random.choice(mask) for piece in pieces]
    result = ''.join(filled)
    return result[0:-1]

mask = '→☺☻♥♦♣♠•◘○§¶▬↨↑↓←∟↔'
example = "Let's take extra spaces. Here's 10:          "
x = swap_characters(example, ' ', mask)
print(x)

Result:
Let's←take¶extra☻spaces.♣Here's↨10:↑↓∟◘§☻↓☻↓◘

The reverse is a more common scenario with a variety of options. For example:

x = swap_characters(example, ' ', mask)
print(x)
for char in mask:
    x = x.replace(char, ' ')
print(x)

Result:
Let's↓take←extra¶spaces.☺Here's☺10:♠§◘☻☺▬☺→¶←
Let's take extra spaces. Here's 10:

Alternatively using regular expressions:

import re
x = swap_characters(example, ' ', mask)
print(x)
set = '|'.join(mask)
x = re.sub(set, ' ', x)
print(x)

Result:
Let's•take¶extra↔spaces.○Here's↓10:♦↔∟♦◘♥••♣→
Let's take extra spaces. Here's 10:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.