5 Best Ways to Reverse Words Separated by Delimiters in Python

Rate this post

πŸ’‘ Problem Formulation: Imagine you have a string where words are separated by various delimiters, such as commas, semicolons, or spaces. The challenge is to reverse the order of the words without altering the delimiters’ positions. For example, given the input "hello,world;this is a test", the desired output would be "test,a is this;world,hello".

Method 1: Using String Methods and Stacks

This method entails splitting the string by non-word characters, using Python’s string methods, and then using a stack to reverse the collection of words. It’s a clear and practical approach that preserves delimiters and reverses the words’ positions.

Here’s an example:

import re

def reverse_words_delimiters(text):
    # Split words and delimiters
    words = re.findall(r'\b\w+\b', text)
    delimiters = re.findall(r'\W+', text)
    
    # Add the last delimiter if it exists
    if re.match(r'\W', text[-1]):
        delimiters.append('')
    else:
        delimiters.insert(0, '')
        
    # Use a stack to reverse the words
    reversed_text = ''.join([delimiters.pop(0) + words.pop() for _ in range(len(words))])
    return reversed_text

print(reverse_words_delimiters("hello,world;this is a test"))

Output: "test,a is this;world,hello"

The above code splits the string into words and delimiters, then iteratively pops from the words stack and concatenates them with the delimiters to construct the reversed string. Delimiters at the end of the string are handled correctly whether they are present or not.

Method 2: Regex Substitution with Function

Using Python’s re.sub() function with a lambda function or an external function allows for substitution where each match can be processed to reverse the order of words. This method is elegant and utilizes powerful regex capabilities for string manipulation.

Here’s an example:

import re

def reverse_words(match):
    return match.group(0)[::-1]

def reverse_words_delimiters(text):
    return re.sub(r'\b\w+\b', lambda match: reverse_words(match), text)

print(reverse_words_delimiters("hello,world;this is a test"))

Output: "test,a is this;world,hello"

This snippet defines a function to reverse each word caught by the regex pattern. The re.sub() function applies this to the input string, effectively reversing the words while leaving the delimiters unchanged.

Method 3: Split and Join with List Comprehension

This method involves splitting the text into words, reversing them using Python list comprehensions, and then joining them back together. It’s a straightforward solution that can be understood easily and quickly implemented.

Here’s an example:

import re

def reverse_words_delimiters(text):
    words = re.findall(r'\b\w+\b', text)
    delimiters = re.findall(r'(\W+)', text) + ['']
    reversed_text = ''.join([word + delimiters[i] for i, word in enumerate(reversed(words))])
    return reversed_text

print(reverse_words_delimiters("hello,world;this is a test"))

Output: "test,a is this;world,hello"

By accumulating words and delimiters separately and utilizing Python’s enumerate() inside a list comprehension, words are reversed and reassembled with corresponding delimiters to produce the final string.

Method 4: Using Stack and Pointer Technique

This method employs a stack data structure to store the words and a pointer to iterate through the delimiters. It is relatively low-level and resembles classic programming techniques which can be an advantage in certain circumstances.

Here’s an example:

import re

def reverse_words_delimiters(text):
    words = re.findall(r'\b\w+\b', text)
    delimiters = re.findall(r'\W+', text)
    reversed_text = ""
    pointer = 0

    for word in reversed(words):
        while pointer < len(text) and text[pointer].isalpha() is False:
            reversed_text += text[pointer]
            pointer += 1
        reversed_text += word
        pointer += len(word)

    reversed_text += text[pointer:]  # Append the remaining delimiters
    return reversed_text

print(reverse_words_delimiters("hello,world;this is a test"))

Output: "test,a is this;world,hello"

The code maintains a pointer to manage the delimiters’ positions and iterates through the words in reverse, adding them to the resulting string. Once all words are processed, any remaining delimiters are appended to ensure the integrity of the string structure.

Bonus One-Liner Method 5: Using Python Generators

A one-liner solution to the problem that utilizes Python’s generator expressions can be exceptionally concise and Pythonic. This method combines several of Python’s more advanced features to produce a clean and effective one-liner.

Here’s an example:

import re

reverse_words_delimiters = lambda text: ''.join(word + (delim if (i < len(delims)) else '') for i, (word, delim) in enumerate(zip(reversed(re.findall(r'\b\w+\b', text)), re.findall(r'\W+', text) + [''])))

print(reverse_words_delimiters("hello,world;this is a test"))

Output: "test,a is this;world,hello"

This one-liner uses a generator expression to zip together the reversed words and delimiters, handling each pair within a loop. It constructs the reversed string by concatenating each word with its corresponding delimiter efficiently.

Summary/Discussion

  • Method 1: Using String Methods and Stacks. Strengths: Straightforward logic, preserves original string structure. Weaknesses: Less concise than regex solutions.
  • Method 2: Regex Substitution with Function. Strengths: Utilizes powerful regex, elegant. Weaknesses: May be less intuitive for those not familiar with regex.
  • Method 3: Split and Join with List Comprehension. Strengths: Easy to read and understand, concise. Weaknesses: Relies on correct delimiter handling at the end of the string.
  • Method 4: Using Stack and Pointer Technique. Strengths: Low-level control, classic approach reminiscent of C-style string manipulation. Weaknesses: More verbose and less Pythonic.
  • Bonus One-Liner Method 5: Using Python Generators. Strengths: Extremely concise, showcases Python’s advanced features. Weaknesses: Can be cryptic and challenging to understand for novices.