4

The function I have to build is meant to replace digits in a string by (value of digit * next character).

So, foo = '2 hs4q q2w2 ' will become ' hsqqqq qww ' (mind the spaces)

Assumption - Digit can't be zero.

I fetched the (index,value) of digits and next char. Used that info to get the substrings I need to put back into the string:

foo = '2 hs4q q2w2 '
parameters=[(int(foo_list[b]),b+1) for b in range(len(foo_list)) if foo_list[b].isdigit()]
parameters # list of tuples (digit,charindex to be extended)
#[(2, 1), (4, 5), (2, 9), (2, 11)]
for p,i in parameters:
 hoo=p*foo[i]
 print (hoo,type(hoo))
 #Out
 <class 'str'> # Two spaces
qqqq <class 'str'>
ww <class 'str'>
 <class 'str'> # Two spaces

How can I use all this info in a loop that works with similar strings? I understand strings are immutable, hence a new str object has to be created for every insert/replace. Plus the index values change as the loop runs.

Comments after solution -

Thank you all for four different kinds of solutions, here is a reference for anyone who hasn't used yield from, yield - In practice, what are the main uses for the new "yield from" syntax in Python 3.3?

asked May 27, 2018 at 0:38

5 Answers 5

3

Single digit numbers

You can check if a character is a digit with str.isdigit, if it is then cast it to an int and multiply it with the next character. This logic can be written as a generator given to str.join.

Code

def expand_string(s):
 return ''.join([(int(c) - 1) * s[i+1] if c.isdigit() else c for i, c in enumerate(s)])

Example

foo = '2 hs4q q2w2 '
print(expand_string(foo)) # ' hsqqqq qww '

Although, the above fails for a string with multiple digit number such as f10o'.

Multiple digits numbers

If you also want to consider numbers with multiple digits, you can write a generator function that groups digits together using itertools.groupby.

Code

from itertools import groupby
def group_digits(s):
 for isdigit, group in groupby(s, str.isdigit):
 yield from [''.join(group)] if isdigit else group
def expand_string(s):
 s = list(group_digits(s))
 return ''.join((int(c) - 1) * s[i+1] if c.isdigit() else c for i, c in enumerate(s))

Example

foo = 'f10o'
print(expand_string(foo)) # 'foooooooooo'
answered May 27, 2018 at 1:22
Sign up to request clarification or add additional context in comments.

Comments

3

You can use re.sub:

import re
foo = '2 hs4q q2w2 '
new_foo = re.sub('\d+[\w\W]{1}', lambda x:x.group()[-1]*int(x.group()[:-1]), foo)

Output:

' hsqqqq qww '
answered May 27, 2018 at 1:20

Comments

1

One idea is to iterate characters in your string pairwise using zip (or itertools.zip_longest) and yield an item depending on whether the character is a digit.

from itertools import zip_longest, islice
foo = '2 hs4q q2w2 '
def gen(x):
 for i, j in zip_longest(x, islice(x, 1, None), fillvalue=''):
 if i.isdigit():
 yield j * (int(i)-1)
 else:
 yield i
res = ''.join(list(gen(foo)))
# ' hsqqqq qww '
answered May 27, 2018 at 0:58

Comments

1

Be careful while using next index in the current iteration, It can give you error because if the string is something like foo = '2 hs4q q2w2 2' Use try and except

foo = '2 hs4q q2w2 '
splitted_data=list(foo)
for i,j in enumerate(splitted_data):
 try:
 if j.isdigit():
 splitted_data[i]=splitted_data[i+1]*int(j)
 except IndexError:
 pass
print("".join(splitted_data))

output:

 hsqqqqq qwww 
answered May 29, 2018 at 15:36

Comments

0

Such a function can be obtained using a while loop:

def new_string(string):
 # Create the variable new_string
 new_string = ""
 i = 0
 while i < len(string):
 char = string[i]
 # If char is a digit we multiply the next char by it
 if char.isdigit():
 new_string += int(char)*string[i+1]
 i += 2
 # If not we just concatenate char
 else:
 new_string += char
 i += 1
 return new_string

Hope it helps.

answered May 27, 2018 at 1:01

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.