Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I have a file and I want to reverse all word in it.

ex input file:

DCBA. HGFE.GI
MLK,PON.RQ
UTS. ZYXWV. 321

ex output file: (What I Want)

ABCD. EFGH.IG
KLM,NOP.QR
STU. VWXYZ. 123

With this sed script: sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' all the entire line is reversed.

The wrong output produced by the command above:

IG.EFGH .ABCD    
QR.NOP,KLM    
123 .VWXYZ .STU 

How can I get my desired output?

share|improve this question
    
I don't understand your second sentence, it sounds like you don't want to reverse certain lines, but I can't tell which ones. Could you clarify? –  Seth Aug 22 at 14:45
    
There should be a . in his second line of input. –  prakharsingh95 Aug 22 at 14:57
    
As it stands, this isn't going to work. At the end of line one, you want to over-run into the next line. At the end of line two, you want to assume an implied end of sentence. To have it both ways is beyond text-processing, and requires a tool which understands grammar. –  Shaun Aug 22 at 15:00
    
You didn't clarify your second sentence, but I think I get it now. Are all the "words" going to have spaces between them? –  Seth Aug 22 at 15:09
    
@Seth No it can be have no space between them –  KasiyA Aug 22 at 15:18

3 Answers 3

up vote 7 down vote accepted

Try this one in pure bash

#!/bin/bash
while IFS= read -N1 char; do
    if [[ "$char" =~ [[:alnum:]] ]]; then
        word="$char$word"
    else
        echo -n "$word$char"
        word=""
    fi
done <input.file >output.file

Output :

ABCD. EFGH.IG
KLM,NOP.QR
STU. VWXYZ. 123

This code logic is quite simple. We read the file character by character (thanks to the -N1 flag. The IFS= is needed to be able to read newlines as well), then we add every valid character we encounter at the begining of the $word variable (thus reversing the word). When we encounter a non-alphanumeric character, we echo the value of $word and reset the value to empty. We repeat those steps until the end of the file

share|improve this answer
1  
Glad it helped ;) I removed it when I updated my answer with [[:alnum:]], as this is a special class that include also non-english characters –  Ploutox Aug 22 at 16:29
    
I'm surprised to read that the perl solution didn't work for non-English words. Under the hood, I would expect it and the bash solution to use almost identical sets of characters (perl's \w versus [:alnum:] should differ only by underscore). What is the output of env | grep '^L\(C\|ANG\)'? –  glenn jackman Aug 22 at 18:51

So, you really want to reverse each word, not each sentence, right? Or is your comma supposed to be a period?

perl -pe 's/(\w+)/ reverse $1 /eg' << END
DCBA. HGFE.GI
MLK,PON.RQ
UTS. ZYXWV. 321
END
ABCD. EFGH.IG
KLM,NOP.QR
STU. VWXYZ. 123

If you want to redirect, do this:

perl -pe 's/(\w+)($|\W+)/ reverse($1) . $2 /eg' < file_in > file_out

With my example, do

perl -pe 's/(\w+)($|\W+)/ reverse($1) . $2 /eg' << END > file_out

DO NOT put the redirection on the same line as the terminating word of the heredoc. If you do, the shell will not be able to find the end of the heredoc.

With redirecting to and from files, never do this: command < file > file with the same file. The redirections happen before the command starts, and > will truncate the file to zero length. When the command starts, the input file has already been destroyed.

share|improve this answer
    
How can I save the output directly to a file? –  KasiyA Aug 22 at 15:59
    
@KasiyA simply use a redirection. On the last line, just write END >output.file (this is valid for other answers as well). Note that glenn's answer uses a heredoc (the <<END ... END syntax). If you have a real file, you should call his command like this : perl -pe '... /eg'<input.file >output.file –  Ploutox Aug 22 at 16:03
2  
Don't put the redirection on the last line, use the first line. Explained in my answer –  glenn jackman Aug 22 at 16:37

And the verbose (python) option:

#!/usr/bin/env python3

with open("/path/to/sourcefile") as messed_up:
    lines = [list(line.replace("\n", "")) for line in messed_up]

def reverse_line(l):
    i=0; line = ""; sep = (" ", ",",".")
    while i < len(l):
        word = []
        while not l[i] in sep:
            word.append(l[i]); i = i+1
            if i == len(l):
                line = line + ("").join(reversed(word)); break
        else:
            line = line + ("").join(reversed(word)) + l[i]
        i = i+1
    print(line)

for l in lines:
    reverse_line(l)

Outputs:

ABCD. EFGH.IG
KLM,NOP.QR
STU. VWXYZ. 123

Lines are "built up" from left to right; characters in the sep list (spaces, commas, dots or any other defined-) and single other characters are placed directly into the line, a consecutive number of other characters are collected first and reversed before they are added to the line.

share|improve this answer
1  
Works fine, also for non-English language. thanks –  KasiyA Aug 22 at 21:03

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.