Write a functon to modify a certain string in a certain way by adding character

Viewed 652

I have to write a function that takes a string, and will return the string with added "asteriks" or "*" symbols to signal multiplication.

As we know 4(3) is another way to show multiplication, as well as 4*3 or (4)(3) or 4*(3) etc. Anyway, my code needs to fix that problem by adding an asterik between the 4 and the 3 for when multiplication is shown WITH PARENTHESIS but without the multiplication operator " * ".

Some examples:

  • "4(3)" -> "4*(3)"
  • "(4)(3)" -> "(4)*(3)"
  • "4*2 + 9 -4(-3)" - > "4*2 + 9 -4*(-3)"
  • "(-9)(-2) (4)" -> "(-9)*(2) *(4)"
  • "4^(3)" -> "4^(3)"
  • "(4-3)(4+2)" -> "(4-3)*(4+2)"
  • "(Aflkdsjalkb)(g)" -> "(Aflkdsjalkb)*(g)"
  • "g(d)(f)" -> "g*(d)*(f)"
  • "(4) (3)" -> "(4)*(3)"

I'm not exactly sure how to do this, I am thinking about finding the left parenthesis and then simply adding a " * " at that location but that wouldn't work hence the start of my third example would output "* (-9)" which is what I don't want or my fourth example that would output "4^*(3)". Any ideas on how to solve this problem? Thank you.

Here's something I've tried, and obviously it doesn't work:

while index < len(stringtobeconverted)
    parenthesis = stringtobeconverted[index]
    if parenthesis == "(":
        stringtobeconverted[index-1] = "*"
5 Answers
In [15]: def add_multiplies(input_string): 
    ...:     return re.sub(r'([^-+*/])\(', r'\1*(', input_string) 
    ...:      
    ...:      
    ...:                                                                                                                                    

In [16]: for example in examples: 
    ...:     print(f"{example} -> {add_multiplies(example)}") 
    ...:                                                                                                                                    
4(3) -> 4*(3)
(4)(3) -> (4)*(3)
4*2 + 9 -4(-3) -> 4*2 + 9 -4*(-3)
(-9)(-2) (4) -> (-9)*(-2) *(4)
4^(3) -> 4^*(3)
(4-3)(4+2) -> (4-3)*(4+2)
(Aflkdsjalkb)(g) -> (Aflkdsjalkb)*(g)
g(d)(f) -> g*(d)*(f)
(g)-(d) -> (g)-(d)

tl;dr Rather than thinking of this as string transformation, you might:

  1. Parse an input string into an abstract representation.

  2. Generate a new output string from the abstract representation.


Parse input to create an abstract syntax tree, then emit the new string.

Generally you should:

  1. Create a logical representation for the mathematical expressions.
    You'll want to build an abstract syntax tree (AST) to represent each expression. For example,

    2(3(4)+5)

    could be form a tree like:

      *
     /  \
    2    +
        /  \
       *    5
      /  \
     3    4
    

    , where each node in that tree (2, 3, 4, 5, both *'s, and the +) are each an object that has references to its child objects.

  2. Write the logic for parsing the input.
    Write a logic that can parse "2(3(4)+5)" into an abstract syntax tree that represents what it means.

  3. Write a logic to serialize the data.
    Now that you've got the data in conceptual form, you can write methods that convert it into a new, desired format.


Note: String transformations might be easier for quick scripting.

As other answers have shown, direct string transformations can be easier if all you need is a quick script, e.g. you have some text you just want to reformat real quick. For example, as @PaulWhipp's answer demonstrates, regular expressions can make such scripting really quick-and-easy.

That said, for professional projects, you'll generally want to parse data into an abstract representation before emitting a new representation. String-transform tricks don't generally scale well with complexity, and they can be both functionally limited and pretty error-prone outside of simple cases.

I'll share mine.

def insertAsteriks(string):

    lstring = list(string)
    c = False

    for i in range(1, len(lstring)):

        if c:
            c = False
            pass
        elif lstring[i] == '(' and (lstring[i - 1] == ')' or lstring[i - 1].isdigit() or lstring[i - 1].isalpha() or (lstring[i - 1] == ' ' and not lstring[i - 2] in "*^-+/")):
            lstring.insert(i, '*')
            c = True

    return ''.join(lstring)

Let's check against your inputs.

print(insertAsteriks("4(3)"))
print(insertAsteriks("(4)(3)"))
print(insertAsteriks("4*2 + 9 -4(-3)"))
print(insertAsteriks("(-9)(-2) (4)"))
print(insertAsteriks("(4)^(-3)"))
print(insertAsteriks("ABC(DEF)"))
print(insertAsteriks("g(d)(f)"))
print(insertAsteriks("(g)-(d)"))

The output is:

4*(3)
(4)*(3)
4*2 + 9 -4*(-3)
(-9)*(-2) (4)
(4)^(-3)
ABC*(DEF)
g*(d)*(f)
(g)-(d)

[Finished in 0.0s]

Here is a code tested on your examples :

i = 0
input_string = "(4-3)(4+2)"
output_string = ""

while i < len(input_string):
    if input_string[i] == "(" and i != 0:
        if input_string[i-1] in list(")1234567890"):
            output_string += "*("
        else:
            output_string += input_string[i]
    else:
        output_string += input_string[i]
    i += 1

print(output_string)

The key here is to understand the logic you want to achieve, which is in fact quite simple : you just want to add some "*" before opening parenthesis based on a few conditions.

Hope that helps !

One way would be to use a simple replacement. The cases to be replaced are:

  • )( -> )*(
  • N( -> N*(
  • )N -> )*N

Assuming you want to preserve whitespace as well, you need to find all patterns on the left side with an arbitrary number of spaces in between and replace that with the same number of spaces less one plus the asterisk at the end. You can use a regex for that.

A more fun way would be using kind of a recursion with fake linked lists:) You have entities and operators. An entity can be a number by itself or anything enclosed in parentheses. Anything else is an operator. How bout something like this: For each string, find all entities and operators (keep them in a list for example) Then for each entity see if there are more entities inside. Keep doing that until there are no more entities left in any entities. Then starting from the very bottom (the smallest of entities that is) see if there is an operator between two adjacent entities, if there is not, insert an asterisk there. Do that all the way up to the top level. The start from the bottom again and reassemble all the pieces.

Related