Open In App

Python – Reverse String except punctuations

Improve
Improve
Like Article
Like
Save
Share
Report

Given a string with punctuations, perform string reverse, leaving punctuations at their places.

Input : test_str = ‘geeks@#for&%%gee)ks’ 
Output : skeeg@#rof&%%ske)eg 
Explanation : Whole string is reversed, except the punctuations.

Input : test_str = ‘geeks@#for&%%gee)ks’ [ only substring reversal ] 
Output : skeeg@#rof&%%eeg)sk 
Explanation : Only substrings are reversed. 
 

Method #1 : Using loop + stack  + punctuation + split()

In this, we use stack to perform string reversal, checking for punctuation, if current character is one, we append that. The split method is used to handle cases of spaces, which needs to be ignored while reverse.

Python3




# Python3 code to demonstrate working of
# Reverse String except punctuations
# Using loop + stack + punctuation + split()
from string import punctuation
 
# initializing string
test_str = 'geeks# for&%% gee)ks'
 
# printing original string
print("The original string is : " + str(test_str))
 
# getting punctuations
punc_set = set(punctuation)
res = []
for sub in test_str.split(' '):
     
    # getting all alphabets
    alphas = [chr for chr in sub if chr not in punc_set]
    for chr in sub:
         
        # checking for punctuations
        if chr not in punc_set:
            res.append(alphas.pop())
            continue
        else:
            res.append(chr)
             
    # handling spaces
    res.append(' ')
res = "".join(res)
 
# printing result
print("The Reversed String ignoring punctuation : " + str(res))


Output

The original string is : geeks#for&%%gee)ks
The Reversed String ignoring punctuation : skeeg#rof&%%ske)eg 

The time complexity is O(n), where n is the length of the input string.

The auxiliary space is also O(n), where n is the length of the input string. 

Method #2 : Using groupby() + isalnum() [ for substring specific reversal ]

In this, we form grouping of each of substring between punctuations and reverse them among them, not whole. The isalnum() is used to check for all the alphabets.

Python3




# Python3 code to demonstrate working of
# Reverse String except punctuations
# Using groupby() + isalnum() [ for substring specific reversal ]
from itertools import groupby
 
# initializing string
test_str = 'geeks# for&%% gee)ks'
 
# printing original string
print("The original string is : " + str(test_str))
 
res = ''
 
# grouping all sections
for ele, sub in groupby(test_str, str.isalnum):
    sub = list(sub)
     
    # reversal on alphanumeric occurrence
    if ele:
        sub = sub[::-1]
         
    # joining all subparts
    res += ''.join(sub)
 
 
# printing result
print("The Reversed String ignoring punctuation [substring] : " + str(res))


The Time and Space Complexity for all the methods are the same:

Time Complexity: O(n2)

Space Complexity: O(n)

Using Two Pointers in python:

Approach:

Create an empty string res and a list of the punctuation characters punc.
Traverse the input string s using two pointers i and j, initialized to the beginning and end of the string, respectively.
While i < j, check if s[i] and s[j] are both alphabetic characters. If they are, swap them.
If s[i] or s[j] is a punctuation character, skip that character and do not move the pointer.
If s[i] and s[j] are both non-alphabetic characters, append them to res without swapping.
Continue steps 3-5 until i >= j.
Return res.

Python3




def reverse_string_except_punctuations(s):
    res = ''
    punc = set('!@#$%^&*()_-+={}[]|\:;"<>,.?/~`')
    i, j = 0, len(s) - 1
    while i < j:
        if s[i].isalpha() and s[j].isalpha():
            res += s[j] + s[i]
            i += 1
            j -= 1
        elif s[i] in punc:
            res += s[i]
            i += 1
        elif s[j] in punc:
            res += s[j]
            j -= 1
        else:
            res += s[i] + s[j]
            i += 1
            j -= 1
    if i == j:
        res += s[i]
    return res
s='geeks# for&%% gee)ks'
print( reverse_string_except_punctuations(s))


Output

sgke)eeekgs#  %%&rfo

Time Complexity: O(n), where n is the length of the input string s. This is because we traverse the string only once.
Auxiliary Space: O(n), where n is the length of the input string s, because we create a new string to store the reversed string.

METHOD 4:USING def .

APPROACH:

In this approach, we first split the input string into words using the split() method. For each word, we initialize two pointers left and right that point to the beginning and end of the word, respectively. We then use a while loop to iterate over the characters of the word, swapping characters at the left and right pointers if they are both letters. We also increment left and decrement right until they cross over or one of them encounters a punctuation character. After reversing the word, we update the word list with the reversed word. Finally, we join the words back together with spaces using the join() method and return the resulting string.

ALGORITHM:

1.Initialize a string containing all the punctuations.
2.Split the input string into a list of words.
3.Iterate through each word in the list.
4.Initialize two pointers, left and right, to the first and last characters of the word respectively.
5.While the left pointer is less than the right pointer, do the following:
      a.If the character at the left pointer is a punctuation mark, move the left pointer to the next character.
      b.If the character at the right pointer is a punctuation mark, move the right pointer to the previous character.
      c.If both characters at the left and right pointers are not punctuation marks, swap them and move the left pointer to the next character and the right pointer to the previous character.
6.Replace the original word with the modified word in the list.
7.Join the list of words back into a string and return it as the result.

Python3




def reverse_except_punctuations(test_str):
    punctuations = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    words = test_str.split()
    for i in range(len(words)):
        word = words[i]
        left, right = 0, len(word)-1
        while left < right:
            if word[left] in punctuations:
                left += 1
            elif word[right] in punctuations:
                right -= 1
            else:
                word = word[:left] + word[right] + word[left+1:right] + word[left] + word[right+1:]
                left += 1
                right -= 1
        words[i] = word
    return " ".join(words)
 
test_str = 'geeks@#for&%%gee)ks'
print(reverse_except_punctuations(test_str))


Output

skeeg@#rof&%%ske)eg

The time complexity of this approach is O(n^2), where n is the length of the input string, since we potentially iterate over each character in each word. 

The auxiliary space is O(n), since we split the input string into a list of words.
 



Last Updated : 23 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads