# DataWeave programming challenge #5: Reverse a phrase's words, but keep the punctuation

> Reverse the order of the words in the given phrases. However, the punctuation signs stay in the same place.

- **Author:** Alex Martinez
- **Published:** Apr 18, 2023
- **Category:** Challenges
- **Tags:** MuleSoft, DataWeave
- **Source:** https://prostdev.com/post/dataweave-programming-challenge-5

---
## Series: DataWeave Programming Challenges (Part 5 of 8)

1. [DataWeave programming challenge #1: Add numbers separated by paragraphs and get the max number](https://prostdev.com/post/dataweave-programming-challenge-1)
2. [DataWeave programming challenge #2: Rock Paper Scissors game score system](https://prostdev.com/post/dataweave-programming-challenge-2)
3. [DataWeave programming challenge #3: Count palindrome phrases using the Strings module](https://prostdev.com/post/dataweave-programming-challenge-3)
4. [DataWeave programming challenge #4: Solve the Tower of Hanoi mathematical puzzle](https://prostdev.com/post/dataweave-programming-challenge-4)
5. DataWeave programming challenge #5: Reverse a phrase's words, but keep the punctuation (this post)
6. [DataWeave programming challenge #6: Using tail-recursion to get the factorial of a number](https://prostdev.com/post/dataweave-programming-challenge-6)
7. [DataWeave programming challenge #7: Modify certain values from a JSON structure](https://prostdev.com/post/dataweave-programming-challenge-7)
8. [DataWeave programming challenge #8: Sum all digits to get a 1-digit number](https://prostdev.com/post/dataweave-programming-challenge-8)

---

> [!NOTE]
> This challenge is based on [Codeacademy's Reverse Words challenge](https://discuss.codecademy.com/t/challenge-reverse-words/83796)

Try to solve this challenge on your own to maximize learning. We recommend you refer to the [DataWeave documentation](https://docs.mulesoft.com/dataweave/latest/) **only**. Try to avoid using Google or asking others so you can learn on your own and become a DataWeave expert!

> [!PLAYGROUND]
> [Solve on the Playground](https://dataweave.mulesoft.com/learn/playground?projectMethod=GHRepo&repo=alexandramartinez%2Fdataweave-challenges&path=challenges%2F5)

## Input

Consider the following input payload (can be of **txt** format):

```
Hello world
May the Fourth be with you
Hello world!
With you, be May the Fourth
With you, be May the Fourth!
```

## Explanation of the problem

Create a DataWeave script that will reverse the order of each one of the words in a phrase to form a new phrase. Each phrase or sentence is separated by a new line. Each word is separated by a space. However, the punctuation signs (! and ,) will have to stay in the same place. Lower/upper cases can be kept as-is.

For example:

- "Hello world!" becomes "world Hello!"
- "With you, be May the Fourth!" becomes "Fourth the, May be you With!"

## Expected output

In this case, the expected output would be:

```
[
  "world Hello",
  "you with be Fourth the May",
  "world Hello!",
  "Fourth the, May be you With",
  "Fourth the, May be you With!"
]
```

> [!NOTE]
> You can keep the output as a JSON or as a text, whatever your preference is.

## Clues

If you're stuck with your solution, feel free to check out some of these clues to give you ideas on how to solve it!

### Clue #1

Keep the index of each punctuation sign so you can insert it there later

### Clue #2

You can use the isAlphanumeric function from the Strings module

### Clue #3

You can use the scan function to separate each phrase in an Array of Strings

### Clue #4

You can use the joinBy function to transform from Array to String

## Answer

If you haven't solved this challenge yet, we encourage you to keep trying! It's ok if it's taking longer than you thought. We all have to start somewhere ✨ Check out the clues and read the docs before giving up. You got this!! 💙

There are many ways to solve this challenge, but you can find here my solution. I'm sure you all can make it better! :) Mine is super long 😂

### Solution #1

```dataweave
%dw 2.0
import slice from dw::core::Arrays
import lines, isAlphanumeric from dw::core::Strings
output application/json
---
lines(payload) 
map ((line) -> flatten(
	line scan /[^\w\d\s]|[\w]*/
) filter (!isEmpty($)))
map ((words) -> do {
	var wordsobj = (words map {
		word: $,
		originalIndex: $$,
		move: isAlphanumeric($)
	})
	var reversed = (wordsobj filter ($.move))[-1 to 0]
	var spechars = wordsobj filter (not $.move)
	var endingStr = if (spechars[-1].originalIndex != null)
			(reversed[spechars[-1].originalIndex to -1].word default [] joinBy " ")
		else ""
	---
	if (isEmpty(spechars)) reversed.word joinBy " "
	else spechars map ((charobj,coidx) ->
		slice(
			reversed,
			if (coidx-1 >= 0) spechars[coidx-1].originalIndex else 0,
			charobj.originalIndex
		).word joinBy " "
		then trim("$($)$(charobj.word) $(endingStr)")
	) joinBy " "
})
```

I also recorded myself coming up with the solution, but without explanations. Just some lo-fi music and a screen :) you can leave the video in the background while working! :D let me know if you find this useful.

Subscribe to receive notifications as soon as new content is published ✨

---

## Reader notes

**decipherMiddleware** (Aug 16, 2023): My approach 🤓

```dataweave
%dw 2.0
import * from dw::core::Strings
output application/json
fun extract(text)=
do {
    var list= words(text)
    var punc= list map (if(isAlphanumeric($)) "" else $[-1])
    var rev= list[-1 to 0] map ((if(isAlphanumeric($)) $ else $[0 to -2]) ++ punc[$$])
    ---
    rev joinBy(" ")
}

---
payload splitBy("\n") map (line,key)-> extract(line)
```

**Felix Schnabel** (Apr 18, 2023): My solution:




```dataweave
%dw 2.0
output application/json
import * from dw::core::Strings
---
lines(payload) map (
  words($) map [$, $$] reduce ((cur, acc = words($)[-1 to 0]) ->
  if(!isAlphanumeric(cur[0][-1]))
    acc update {
      case [cur[1]] -> $ ++ cur[0][-1] as String
      case [sizeOf(acc) - cur[1] - 1] -> $[0 to -2]
    }
  else
    acc
  ) joinBy " "
)
```

My first approach was wrong, I just inserted the special chars at the exact index where they were before 😂

So "a, bc" would be "b,c a" what's wrong of course


**Shyam Raj Prasad** (Apr 18, 2023): My approach for this.

```dataweave
%dw 2.0
output application/json
import * from dw::core::Strings
---
/* Expected output:
[
  "world Hello",
  "you with be Fourth the May",
  "world Hello!",
  "Fourth the, May be you With",
  "Fourth the, May be you With!"
]
*/
(payload splitBy  "\n") map (
  do {
      var  y = $ splitBy  " " map ($ filter isAlphanumeric($))
      var x =($ splitBy " ") map if(isAlphanumeric($)) "" else $ filter !(isAlphanumeric($))
  ---
  y [-1 to 0] map (
    $ ++ x[$$] 
   ) joinBy  " "
  }
)
```

↳ Reply to Shyam Raj Prasad — **Alex Martinez** (Apr 18, 2023): OH MY GOD SO EASY!!! Love it!!!

↳ Reply to Shyam Raj Prasad — **Felix Schnabel** (Apr 18, 2023): Damn, that solution is so nice.
I was kinda thinking in that direction but couldn't write it down


---

## FAQs

### What does this DataWeave challenge ask you to do?

You write a DataWeave script that reverses the order of the words in each phrase to form a new phrase, where phrases are separated by a new line and words are separated by a space, but the punctuation signs (`!` and `,`) stay in the same place; for example "Hello world!" becomes "world Hello!" and "With you, be May the Fourth!" becomes "Fourth the, May be you With!". Lower and upper cases can be kept as-is.

### How should the punctuation be handled when reversing the words?

The punctuation signs stay in the same place rather than moving with the words, so as Clue #1 suggests you keep the index of each punctuation sign so you can insert it back there later after the words have been reversed.

### What clues does the post give if I get stuck?

The post offers four clues: first, keep the index of each punctuation sign so you can insert it there later; second, you can use the `isAlphanumeric` function from the Strings module; third, you can use the `scan` function to separate each phrase into an Array of Strings; and finally you can use the `joinBy` function to transform from Array to String.

### Can I output the result as text instead of JSON?

Yes, the post notes you can keep the output as a JSON or as a text, whatever your preference is.

### Where can I try solving this challenge?

You can solve it on the DataWeave Playground using the linked project at https://dataweave.mulesoft.com/learn/playground?projectMethod=GHRepo&repo=alexandramartinez%2Fdataweave-challenges&path=challenges%2F5, and the post recommends referring only to the DataWeave documentation at https://docs.mulesoft.com/dataweave/latest/ rather than Google or others so you can learn on your own.