简体   繁体   中英

Modify characters between two symbols in a string

Here is my problem, I have to write a function that receives a string and returns that string with the characters between "*" in uppercase, for example given that string: “I want *this text* to be uppercase” , it returns : “I want THIS TEXT to be uppercase” . Here is the code that I have written:

l = []
def func(s):
    inside = False
    for i in s:
        if i == "*" and not inside:
            inside = True
            while inside:
                if i == "*":
                    inside = False
                else:
                    i.upper()
    l.append(i)
            
    print(s)
                

When I run the program it prints out the text without any change. What am I doing wrong? Thanks

I think you've tried to make this more complicated than it is. You need to find the index of both asterisks. From that you can get three slices of the original string and apply upper() to the slice between the asterisks. Note that this code will fail if there are fewer than two asterisks in the string.

def dotricks(s):
    i = s.index('*')
    j = s.index('*', i+i)
    return s[0:i] + s[i+1:j].upper() + s[j+1:]

print(dotricks('I want *this text* to be uppercase'))

There are several issues here:

  1. You don't return anything inside your function
  2. Your while loop is pointless as i is not incremented inside of it
  3. You need to assign i to i.upper()
  4. You need to convey the input to a list

The corrected code would be as follows:

l = []
def func(s):
    inside = False
    for i in s:
        if i == "*" and not inside:
            inside = True
            while inside:
                if i == "*":
                    inside = False
                else:
                    i.upper()
        if i != "*":
            l.append(i)
    return l

You are not changing the string in your code. In this edit below, I've assigned the letters of the string to a new variable. And used continue to skip over the "*". Also, at the end your append will give you a list of letters which you need to use .join() to concatentate.

Try this edit to your code, tested and working :

l = []
def func(s):
    inside = False
    temp = ""
    for i in s:
        if i == "*" and not inside:
            inside = True
            continue
        if inside:
            if i == "*":
                inside = False
                continue
            else:
                temp = i.upper()
        else:
            temp = i
        l.append(temp)
            
    new_string = "".join(l)
    print(new_string)
    return new_string

func("I want *this text* to be uppercase")

By splitting the string at the character * then the uppercase entry is the odd one, then joining together. It is supposed that there are always an even number of * so it should be considered a kind of reserved character.

s = "I want *this text* to be uppercase and *this* as well"

print(' '.join((j.upper() if i%2!=0 else j for i, j in enumerate(s.split('*')))))

Output

I want  THIS TEXT  to be uppercase and  THIS  as well

First, this function isn't doing anything to s , so print(s) will print whatever was input, unchanged.

Second, the while inside loop needs to be outside of that if statement - right now, it's only accessed when i is an asterisk. Decrease that whole block's indent by one, and change while inside to if inside - that way, that code is executed for all values of i when inside is true.

Next, you need a way to signal when a second asterisk is reached, or a third, and so on. How about instead of assigning inside to True if i is an asterisk and inside is False, you swap the value of inside every time an asterisk is reached?

if i == '*':
    inside = not inside

This negates any need to mess with changing inside in the second part of your code - it puts all the determining "am I inside/am I outside" logic in one place.

Next, you've declared a list l outside the scope of the function, and it looks like you want to add the edited characters to it so the answer you want is in that list in the end. But you want your answer in a string, not a list, and it's usually bad practice to declare a list in global scope and then edit it during a function call (if you call the function more than once, the list will get messy!). Declare an empty string l = '' at the beginning of the function, and then instead of appending characters to it, you can add them using the += operator.

You also need to make sure you're adding the uppercase version, l += i.upper() or the regular version, l += i , depending on whether or not inside is true. You can put all the code after the if i == '*' line in an else statement to catch all cases that i isn't an asterisk.

Putting it all together, your function can look something like this:

def func(s):
    l = ''                        # the string that will be returned (the result of the function)
    inside = False 
    for i in s:
        if i == "*":              # flip value of inside whenever you see an asterisk
            inside = not inside
        else:                     # otherwise, add i to the result
            if inside:
                l += i.upper()    # uppercase if between two asterisks
            else:
                l += i            # unchanged if not

    return l                      # and return the modified string

Then, to test the function:

my_string = "I want *this text* to be uppercase"
my_string_modified = func(my_string)


print(my_string)
print(my_string_modified)

Output:

I want *this text* to be uppercase
I want THIS TEXT to be uppercase

There are definitely more "advanced" ways to do this, as pointed out in other answers on this post, but I hope this answer has helped to clarify what's going wrong in your code, how to fix it, and what some good practices are when you write this kind of thing. Writing code this way is, in my opinion, a really good way to understand how algorithmic processes can be designed and implemented. Happy coding!

I would leverage the power of the re module:

import re

st = "I want *this text* to be uppercase and *this one*"

v = re.findall("\*(.*?)\*", st)

for s in v:
    st = st.replace(f'*{s}*', s.upper())

print(st)

Output:

>>> I want THIS TEXT to be uppercase and THIS ONE

Anyway, re-editing your code:

def func(s):
    l = []
    inside = False
    for i in s:
        if i == "*": 
            inside = not inside  # switch inside on/off when * is found

        if inside:
            i = i.upper() # upper the character if inside == True
        l.append(i)
    return l

If you look at your original code, part of the problem is in the following logic:

if i == "*" and not inside:
    inside = True  # inside is set to True when * is found....
        while inside:
            if i == "*":
                inside = False # and immediately set to False again!

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