Reversing Words Order with Punctuations Order Unchanged

Reversing Words Order with Punctuations Order Unchanged

ECX 30 Days of Code and Design

Day 18

Reverse Order

Task

Write a function that takes a string as input, and returns a string similar to the input, but with the words in reverse order, and the punctuation marks maintaining their original order. E.g.: f("Hello. I'm Edwin A.J, and you?") => "You. and A.J Edwin I'm, Hello?"
f("What time is it? Hammer time.") => "Time Hammer It is? time what."

Note: As shown in the example above, the order of the punctuation marks ("?", ",", ".") has not changed. Only the words have.

My Approach

Below is the whole code. It would be explained in bits throughout this article.

import re                   # For findall(), compile()
import string               # For punctuation()


def change_word_order(words):
    """Reverse word order with punctuations intact."""
    # Regex containing both words and punctuations
    find_word_punct = re.compile(r'\w+(?:(?:\.|\')\w+)?|["!#$()\[\]%&\'./:?;,<=>]')

    # Regex containing only words
    find_word = re.compile(r'\w+(?:(?:\.|\')\w+)?')

    match_word_punct = find_word_punct.findall(words)
    match_word = find_word.findall(words)

    # Reverse the list of words matched
    reverse_list = list(reversed(match_word))

    # Check for the position of the punctuations
    for index, list_item in enumerate(match_word_punct):
        if list_item in string.punctuation:

            # Insert the punctuations in the word list that was reversed
            reverse_list.insert(index, list_item)

    word_output = ''                # Variable for string the new word order

    # Add the words to the variable. If it is a punctuation mark of the first list item, space is not added before it.
    # If it is a word, space is added before the word.
    for i in reverse_list:
        if i in string.punctuation or i is reverse_list[0]:
            word_output = word_output + i

        else:
            word_output = word_output + ' ' + i

    print(word_output)


print('Print the reverse order of words with punctuation mark(s) left in the same order.')
user_input = input('Enter the word you want its order changed: ')

# Function call
change_word_order(user_input)

First, we import the re and string modules which would be used for the findall() function and string.punctuation respectively.

import re                   # For findall(), compile()
import string               # For punctuation()

Next, we define the function we would use to for reversing the word order whilst maintaining its punctuation mark in its original position. Then using the re module, we create patterns to find both word and punctuation mark. Also, we create a pattern to find only words. r'\w+(?:(?:\.|\')\w+)?' would only find word, acronyms, and words containing apostrophe while r'\w+(?:(?:\.|\')\w+)?|["!#$()\[\]%&\'./:?;,<=>]' would find words, acronyms, words containing apostrophe, and punctuation marks. def change_word_order(words): find_word_punct = re.compile(r'\w+(?:(?:.|\')\w+)?|["!#$()[]%&\'./:?;,<=>]')

find_word = re.compile(r'\w+(?:(?:\.|\')\w+)?')

Next, we use the findall() function for both match patterns, thus creating a list containing only the words, and a list containing both the words and punctuations. We then reverse the order of the list containing only the words.

    match_word_punct = find_word_punct.findall(words)
    match_word = find_word.findall(words)

    reverse_list = list(reversed(match_word))

Next, using the enumerate() function with the list containing both words and punctuations, we find the index of the punctuations, which we insert in the list containing only words.

    for index, list_item in enumerate(match_word_punct):
        if list_item in string.punctuation:

            reverse_list.insert(index, list_item)

We create a variable, word_output, which would store the new sentence(s). We then add the words and punctuations together. If the next list item is a punctuation mark, we add it without a space, but if it is a word, a space is added before the word is added to the word_output variable. When we are done, adding the words, we print it out.

    word_output = '' 
    for i in reverse_list:
        if i in string.punctuation or i is reverse_list[0]:
            word_output = word_output + i

        else:
            word_output = word_output + ' ' + i

    print(word_output)

Finally, we instruct the user on what to do and collect their input. Their input is passed as the argument of the change_word_order() function which outputs the required result.

print('Print the reverse order of words with punctuation mark left in the same order.')
user_input = input('Enter the word you want its order changed: ')

change_word_order(user_input)

Output

If we enter “Today is Sunday, isn't it? Yes, it is.,” we get;

Print the reverse order of words with punctuation mark(s) left in the same order.
Enter the word you want its order changed: Today is Sunday, isn't it? Yes, it is.
is it Yes, it isn't? Sunday, is Today.

Run the code on Replit.