简体   繁体   中英

How to shuffle letters in string with vowel isolated in Python

I am creating a function

  1. Takes input as a string.
  2. Returns a string.
  3. The return string will have the same number of words as the input string, and the same letters as the input string, but the individual words can be of different length. ie

     perm_lets("try this") == "ist thry"

is a valid return-value. By "number of words" in a string X , we mean the length of the list X.split(' ') , ie one more than the number of blank spaces in the string. A "word" means a string of letters with no spaces. Lastly,

  1. Every vowel must be isolated, ie immediately beside vowels you have at most spaces and/or consonants.

My function can only shuffle the letters of the input string. I would like to know how to isolate the vowel

    import random as rd
    def perm_lets(input_string):
        nS = ''.join(rd.sample(input_string,len(input_string)))
        print(nS)

I expect the output of perm_lets("this is a loop") to be something like "si olo pit ahs" but the actual output is " ph siioaos lt" (spaces in the wrong place and vowels are not isolated).

Brute force randomization with disqualifying tests:

import re
import random
import time

def perm_lets(s):
    s = list(s)
    start = time.perf_counter()
    while True:
        random.shuffle(s)
        p = ''.join(s)
        if '  ' in p: continue                            # no spaces together
        if p.startswith(' ') or p.endswith(' '): continue # don't start or end with space
        if re.search(r'[aeiou]{2}',p): continue           # no vowels together
        elapsed = time.perf_counter() - start
        return p,elapsed

print(perm_lets('this is a loop'))
print(perm_lets('i bid you adieu'))

Output (4 runs):

('sopihats o i l', 0.0009378000000026532)
('ade udo ibiyi u', 0.07766600000000068)
('i o ha tpsislo', 0.00026450000000011187)
('o adebudu iyi i', 0.00632540000000148)
('o la sstipi ho', 5.2900000000022374e-05)
('udobida eyi i u', 0.3843909999999937)     # 1/3 of a second for a tough sentence
('ipa hts o soli', 0.00028810000000589753)
('idida e obu uyi', 0.18083439999999484)

Note: "adieu louie" has no solution.

Here is one way to attempt what you are after. Separates vowels from consonants, shuffles them for randomness, zips vowels and consonants in a poor attempt to isolate the vowels (but this will fail if there are too many more vowels than consonants), randomly selects word length ensuring minimum of one character per word and that the number of output words is the same as the number of input words.

You could probably do a better job isolating vowels by generating more single vowel words when necessary. However, depending on the vowel to consonant ratio and the number of words, there will always be scenarios where you can't both isolate vowels and output the desired number of words.

from itertools import chain, zip_longest
from random import randint, random, shuffle

s = 'this is a loop'

vowels = []
consonants = []
for char in s.replace(' ', ''):
    if char in 'aeiouAEIOU':
        vowels.append(char)
    else:
        consonants.append(char)

shuffle(vowels)
shuffle(consonants)
if len(vowels) > len(consonants) or random() > 0.5:
    a, b = vowels, consonants
else:
    a, b = consonants, vowels

letters = ''.join([c for c in chain.from_iterable(zip_longest(a, b)) if c])
words = []
for i in range(s.count(' '), -1, -1):
    x = randint(1, len(letters) - i)
    words.append(letters[:x])
    letters = letters[x:]

s = ' '.join(words)
print(s)
# EXAMPLE RANDOM OUTPUT:
# si hipa lo tos

you can do it like this also

  • separate vowels and consonant using regex
  • combine each vowels to consonant
  • shuffle the result until result not starts/ends with space and don't have two spaces together
import random
import re

def perm_lets(st):
    ls = re.findall(r"([aeiouAEIOU])|(.)", st)
    vs, cs = [c for c,_ in ls if len(c)>0], [v for _,v in ls if len(v)>0]

    positions = list(range(len(cs)))
    result = ""
    for v in vs:
        if len(positions)==0:
            cs.append(" "+v)
        else:
            p = random.choice(positions)
            positions.remove(p)
            cs[p//2] += v

    while True:
        random.shuffle(cs)
        result = "".join(cs)
        if not (result.startswith(" ") or result.endswith(" ") or "  " in result):
            break

    return result



print(perm_lets("this is a loop"))

print(perm_lets("teis iou")) # more vowels than consonants

Output

tp so hal osii
si u tei o

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