0

I'm struggling to understand a seemingly simple problem. What I want to do is to change a string slightly, by wrapping all the values inside a separator such as parentheses () with a character like quotes, and then title casing all the words. But I'm unable to get it to fully working as expected.

For example, given a simple string:

hello(world)

I want to replace the part inside the paranthesis by modifying it slightly - in this case by wrapping it with quotes:

hello("World")

I'm able to get this far, but the problem is it's not working when I have nested parantheses:

hi (hello(world(a test)))

I would like to end up with:

hi ("Hello("World("A Test")")")

But I'm not getting a result as expected ufortunately.

Here's my code that I was testing with. By the way, I got the idea to get the indices of a character in a string from this article here.

import re

def wrap_values_within_group(s: str, delimiter_group='()'):
    start_char, end_char = delimiter_group
    start_indices = [i.start() for i in re.finditer(re.escape(start_char), s)]
    end_indices = [i.start() for i in re.finditer(re.escape(end_char), s)]

    parts = []
    for i in range(len(start_indices)):
        start_pos = start_indices[i]
        end_pos = end_indices[-i]
        repl_pos = start_pos + 1

        parts.append(s[:repl_pos])
        parts.append('"' + s[repl_pos:end_pos].title() + '"')
        parts.append(s[end_pos:])

    return ''.join(parts)

I understand I can likely achieve this without regex, but I'd like to see if it's possible without using regex substitutions if possible. I'd also prefer to do this within one function ideally, as I'm thinking that calling a function repeatedly to make the replacements might be a bit slow. Any suggestions are welcome.

rv.kvetch
  • 9,940
  • 3
  • 24
  • 53
  • So basically you want to replace every `(` with `("` and every `)` with `")`? – mkrieger1 Oct 22 '21 at 20:46
  • @mkrieger1 I didn't think about it like that, but it sounds pretty straightforward when you say it like that. The actual use case is a bit different - let me update the question. – rv.kvetch Oct 22 '21 at 20:47
  • I just updated the post. I should have phrased it better, but I want to also transform the value inside the group (for example by uppercasing each word). – rv.kvetch Oct 22 '21 at 20:51
  • @rv.kvtech is [my answer](https://stackoverflow.com/a/69682941/16343464) working for you? – mozway Oct 22 '21 at 21:02
  • @mozway yes, it does seem to work for me. my actual use case is a bit different as I actually need to retrieve each of the values inside the `()`, since I need to apply a conditional transformation to each one, but I suppose that this does answer the question anyway. – rv.kvetch Oct 22 '21 at 21:12
  • 1
    I'm not sure which kind of transformation you're applying. If you really need to get the full content inside each matching parentheses, you can first read the strings and count/index the opening and closing parentheses, then extract the content and apply your transform. You can do this recursively from out to in. – mozway Oct 22 '21 at 21:19
  • Yes, apologies. It's a bit hard to explain, and that was actually why I was trying to find the indices of each open and closing paranthesis, so I could transform each value based on a condition and then replace it in the actual string. However, I will go ahead and accept your answer, as I agree it it wasn't worded as well as it could have been. – rv.kvetch Oct 22 '21 at 21:23

3 Answers3

1

You could split using lookarounds and join:

import re
s = 'hi (hello(world(a test)))'
'"'.join(re.split('(?<=\()|(?=\))', s))

Output: 'hi ("hello("world("a test")")")'

Example with capitalization:

s = 'hi (hello(world(a test)))'
l = re.split('(?<=\()|(?=\))', s)
'"'.join([s.capitalize() if i not in (0, len(l)-1) else s
 for i,s in enumerate(l)])

Output: 'hi ("Hello("World("A test")")")'

mozway
  • 194,879
  • 13
  • 39
  • 75
0

Basically you only need to replace every ( with (", right side respectively:

txt = "hi (hello(world(a test)))"
txt = txt.replace("(", "(\"").replace(")", "\")")

Note how you can use \"to unescape ".

RawkFist
  • 474
  • 5
  • 12
  • You don't need to escape `"`. You can simply use single quotes: `txt.replace('(', '("').replace(')', '")')` – mapf Oct 22 '21 at 21:10
0

I eventually solved this problem with the help of a little recursion and a helper transform function. It took me a while to get my head wrapped around what I was trying to do. Thanks again to everyone who answered or helped point me in the right direction.

def transform_func(s: str):
    return '"' + s.title() + '"'


def wrap_values_within_group(s: str, delimiter_group='()'):
    start_char, end_char = delimiter_group

    if start_char not in s:
        return s

    start_pos = s.index(start_char)
    end_pos = s.rindex(end_char)

    repl_pos = start_pos + 1
    replaced_val = transform_func(wrap_values_within_group(s[repl_pos:end_pos]))

    return f'{s[:repl_pos]}{replaced_val}{s[end_pos:]}'

Usage:

print(wrap_values_within_group('hello(world)'))
# hello("World")
print(wrap_values_within_group('hi (hello(world(a test)))'))
# hi ("Hello("World("A Test")")")
rv.kvetch
  • 9,940
  • 3
  • 24
  • 53