3

so i need to code a program which, for example if given the input 3[a]2[b], prints "aaabb" or when given 3[ab]2[c],prints "abababcc"(basicly prints that amount of that letter in the given order). i tried to use a for loop to iterate the first given input and then detect "[" letters in it so it'll know that to repeatedly print but i don't know how i can make it also understand where that string ends also this is where i could get it to,which probably isnt too useful:

string=input()
string=string[::-1]
bulundu=6
for i in string:
    if i!="]":
        if i!="[":
            lst.append(i)
        if i=="[":
            break
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
krox
  • 39
  • 1
  • 2
    Are you allowed to use regex? `for cnt, letters in re.findall(r"(\d+)\[([^\]]+)\]", "3[ab]2[c]"): print(letters * int(cnt), end='')` ?? – 001 Dec 06 '21 at 14:15
  • Is `'5[23]'` something you need to be able to do? Is `'22[a]'` something you need to be able to do? – Patrick Artner Dec 06 '21 at 15:30

5 Answers5

0

The approach I took is to remove the brackets, split the items into a list, then walk the list, and if the item is a number, add that many repeats of the next item to the result for output:

import re

data = "3[a]2[b]"
# Remove brackets and convert to a list
data = re.sub(r'[\[\]]', ' ', data).split()

result = []
for i, item in enumerate(data):
  # If item is a number, print that many of the next item
  if item.isdigit():
    result.append(data[i+1] * int(item))

print(''.join(result))
# aaabb
match
  • 10,388
  • 3
  • 23
  • 41
0

A different approach, inspired by Subbu's use of re.findall. This approach finds all 'pairs' of numbers and letters using match groups, then multiplies them to produce the required text:

import re

data = "3[a]2[b]"

matches = re.findall('(\d+)\[([a-zA-Z]+)\]',data)
# [(3, 'a'), (2, 'b')]
for x in matches:
    print(x[1] * int(x[0]), end='')
    #aaabb
match
  • 10,388
  • 3
  • 23
  • 41
0

Lenghty and documented version using NO regex but simple string and list manipulation:

  • first split the input into parts that are numbers and texts
  • then recombinate them again
  • I opted to document with inline comments

This could be done like so:

# testcases are tuples of input and correct result
testcases = [ ("3[a]2[b]","aaabb"), 
              ("3[ab]2[c]","abababcc"), 
              ("5[12]6[c]","1212121212cccccc"), 
              ("22[a]","a"*22)]

# now we use our algo for all those testcases
for inp,res in testcases:

    split_inp = []   # list that takes the splitted values of the input
    num = 0          # accumulator variable for more-then-1-digit numbers
    in_text = False  # bool that tells us if we are currently collecting letters

    # go over all letters : O(n)
    for c in inp:

        # when a [ is reached our num is complete and we need to store it
        # we collect all further letters until next ] in a list that we
        # add at the end of your split_inp
        if c == "[":
            split_inp.append(num)    # add the completed number 
            num = 0                  # and reset it to 0
            in_text = True           # now in text
            split_inp.append([])     # add a list to collect letters

        # done collecting letters 
        elif c == "]":
            in_text = False          # no longer collecting, convert letters
            split_inp[-1] = ''.join(split_inp[-1]) # to text


        # between [ and ] ... simply add letter to list at end
        elif in_text:
            split_inp[-1].append(c) # add letter

        # currently collecting numbers
        else:
            num *= 10      # increase current number by factor 10
            num += int(c)  # add newest number
    
    print(repr(inp), split_inp, sep="\n")  # debugging output for parsing part

    # now we need to build the string from our parsed data
    amount = 0
    result = []  # intermediate list to join ['aaa','bb']

    # iterate the list, if int remember it, it text, build composite
    for part in split_inp:
        if isinstance(part, int):
            amount = part
        else:
            result.append(part*amount)

    # join the parts 
    result = ''.join(result)


    # check if all worked out
    if result == res:
        print("CORRECT:  ", result + "\n")
    else:
        print (f"INCORRECT:  should be '{res}' but is '{result}'\n")
        

Result:

'3[a]2[b]'
[3, 'a', 2, 'b']
CORRECT:   aaabb

'3[ab]2[c]'
[3, 'ab', 2, 'c']
CORRECT:   abababcc

'5[12]6[c]'
[5, '12', 6, 'c']
CORRECT:   1212121212cccccc

'22[a]'
[22, 'a']
CORRECT:   aaaaaaaaaaaaaaaaaaaaaa

This will also handle cases of '5[12]' wich some of the other solutions wont.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

You can capture both the number of repetitions n and the pattern to repeat v in one go using the described pattern. This essentially matches any sequence of digits - which is the first group we need to capture, reason why \d+ is between brackets (..) - followed by a [, followed by anything - this anything is the second pattern of interest, hence it is between backets (...) - which is then followed by a ]. findall will find all these matches in the passed line, then the first match - the number - will be cast to an int and used as a multiplier for the string pattern. The list of int(n) * v is then joined with an empty space. Malformed patterns may throw exceptions or return nothing.

Anyway, in code:

import re

pattern = re.compile("(\d+)\[(.*?)\]")

def func(x): return "".join([v*int(n) for n,v in pattern.findall(x)])

print(func("3[a]2[b]"))
print(func("3[ab]2[c]"))

OUTPUT

aaabb
abababcc

FOLLOW UP

Another solution which achieves the same result, without using regular expression (ok, not nice at all, I get it...):

def func(s): return "".join([int(x[0])*x[1] for x in map(lambda x:x.split("["), s.split("]")) if len(x) == 2])
nikeros
  • 3,302
  • 2
  • 10
  • 26
0

I am not much more than a beginner and looking at the other answers, I thought understanding regex might be a challenge for a new contributor such as yourself since I myself haven't really dealt with regex.

The beginner friendly way to do this might be to loop through the input string and use string functions like isnumeric() and isalpha()

data = "3[a]2[b]"
chars = []
nums = []
substrings = []

for i, char in enumerate(data):
    if char.isnumeric():
        nums.append(char)
    if char.isalpha():
        chars.append(char)

for i, char in enumerate(chars):
    substrings.append(char * int(nums[i]))
string = "".join(substrings)
print(string)

OUTPUT:

aaabb

And on trying different values for data:

data = "0[a]2[b]3[p]"
OUTPUT bbppp


data = "1[a]1[a]2[a]"
OUTPUT aaaa

NOTE: In case you're not familiar with the above functions, they are string functions, which are fairly self-explanatory. They are used as <your_string_here>.isalpha() which returns true if and only if the string is an alphabet (whitespace, numerics, and symbols return false And, similarly for isnumeric()

For example,

  • "]".isnumeric() and "]".isalpha() return False
  • "a".isalpha() returns True

IF YOU NEED ANY CLARIFICATION ON A FUNCTION USED, PLEASE DO NOT HESITATE TO LEAVE A COMMENT

Arnav Mangla
  • 82
  • 1
  • 7