Reverse the order of lines in a text file while preserving the contents of each line
For the input file, use the following five lines (records):
- Task
-
- Read an an entire (input) file (into memory or buffers).
- Display the lines/records of the entire file in reverse order.
- Show the results here, on this page.
"Diplomacy is the art of ◄■■■■■■ starts in column 3. saying 'Nice Doggy' ◄■■■■■■ starts in column 5, until you can find a rock." ◄■■■■■■ starts in column 2, ◄■■■■■■ (a blank line), --- Will Rodgers ◄■■■■■■ starts in column 30.
You can (or may) assume there are no superfluous trailing blanks, and that line four has one blank.
Also, don't include the rightmost informative comments (◄■■■■■■), as they are not meant to be part of the file.
Reference: Bash tac command
Ada
<lang Ada>with Ada.Text_Io; with Ada.Containers.Indefinite_Vectors; with Ada.Command_Line;
procedure Reverse_Lines_In_File is
subtype Line_Number is Natural;
package Line_Vectors is new Ada.Containers.Indefinite_Vectors (Index_Type => Line_Number, Element_Type => String);
use Line_Vectors, Ada.Text_Io, Ada.Command_Line;
File : File_Type; Buffer : Vector;
begin
if Argument_Count = 1 then Open (File, In_File, Argument (1)); Set_Input (File); end if;
while not End_Of_File loop Buffer.Prepend (Get_Line); end loop;
if Is_Open (File) then Close (File); end if;
for Line of Buffer loop Put_Line (Line); end loop;
end Reverse_Lines_In_File;</lang>
ALGOL W
<lang algolw>begin % reverse the order of the lines read from standard input %
% record to hold a line and link to the next % record LinkedLine ( string(256) text; reference(LinkedLine) next ); string(256) line; reference(LinkedLine) lines; % allow the program to continue after reaching end-of-file % ENDFILE := EXCEPTION( false, 1, 0, false, "EOF" ); % handle the input % lines := null; readcard( line ); while not XCPNOTED(ENDFILE) do begin lines := LinkedLine( line, lines ); readcard( line ) end while_not_eof ; % show the lines in reverse order % while lines not = null do begin integer len; % find the length of the line with trailing spaces removed % len := 255; line := text(lines); while len > 0 and line( len // 1 ) = " " do len := len - 1; % print the line, note Algol W does not allow variable length substrings % write( s_w := 0, line( 0 // 1 ) ); for cPos := 1 until len do writeon( s_w := 0, line( cPos // 1 ) ); lines := next(lines) end while_lines_ne_null
end.</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
AWK
<lang AWK>
- syntax: GAWK -f REVERSE_THE_ORDER_OF_LINES_IN_A_TEXT_FILE_WHILE_PRESERVING_THE_CONTENTS_OF_EACH_LINE.AWK filename
{ arr[NR] = $0 } END {
for (i=NR; i>=1; i--) { printf("%s\n",arr[i]) } exit(0)
} </lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Factor
<lang factor>USING: io io.encodings.utf8 io.files sequences ;
"rodgers.txt" utf8 file-lines <reversed> [ print ] each</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Go
<lang go>package main
import (
"bytes" "fmt" "io/ioutil" "log" "runtime"
)
func main() {
fileName1 := "rodgers.txt" fileName2 := "rodgers_reversed.txt" lineBreak := "\n" if runtime.GOOS == "windows" { lineBreak = "\r\n" } // read lines from input file b, err := ioutil.ReadFile(fileName1) if err != nil { log.Fatal(err) } lines := bytes.Split(b, []byte(lineBreak)) // remove final blank line, if any, added by some editors if len(lines[len(lines)-1]) == 0 { lines = lines[:len(lines)-1] }
// write lines in reverse order to output file for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 { lines[i], lines[j] = lines[j], lines[i] } b = bytes.Join(lines, []byte(lineBreak)) if err = ioutil.WriteFile(fileName2, b, 0o666); err != nil { log.Fatal(err) } // print contents of output file to terminal b, err = ioutil.ReadFile(fileName2) if err != nil { log.Fatal(err) } fmt.Println(string(b))
}</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
jq
Works with gojq, the Go implementation of jq <lang sh> jq -nRr '[inputs] | reverse[]' input.txt </lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Julia
The optional
keep
argument to
readlines
means to keep the newline '\n' char or '\r\n' digraph at the end of each line. The
|>
symbolism is the pipe operator. and the
.|>
symbolism means to pipe each line in the read array to print separately. <lang julia>readlines("diplomacyrodgers.txt", keep=true) |> reverse .|> print</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Nim
We provide a procedure which takes input and output files as parameters. Assumptions are the following:
– a line is a sequence of bytes terminated by CR, LF or CR-LF;
– there is enough memory to process the file in memory i.e to store the input file as a string, the sequence of lines, the reverse sequence of lines and the output file as a string. <lang Nim>import algorithm, strutils
proc reverseLines(infile, outfile: File) =
let lines = infile.readAll().splitLines(keepEol = true) outfile.write reversed(lines).join("")
when isMainModule:
let infile = open("reverse_file_lines.txt") echo ">>>>> Input file:" stdout.write infile.readAll() infile.setFilePos(0) echo ">>>>>" echo '\n' echo ">>>>> Output file:" reverseLines(infile, stdout) echo ">>>>>"</lang>
- Output:
>>>>> Input file: "Diplomacy is the art of saying 'Nice Doggy' until you can find a rock." --- Will Rodgers >>>>> >>>>> Output file: --- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of >>>>>
Pascal
maybe
<lang pascal>program TAC; {$IFDEF FPC}
{$MODE DELPHI}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF} uses
sysutils, classes;
var
Sl:TStringList; i,j : nativeInt;
begin
Sl := TStringList.Create; Sl.Loadfromfile('Rodgers.txt'); i := 0; j := Sl.Count-1; While i<j do Begin Sl.Exchange(i,j); inc(i); dec(j); end; writeln(Sl.text);
end.</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Perl
as one-liner .. <lang perl>// 20210803 Perl programming solution
< input.txt perl -e 'print reverse <>'</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Phix
with javascript_semantics string text = """ "Diplomacy is the art of saying 'Nice Doggy' until you can find a rock." --- Will Rodgers""" if platform()!=JS then integer fn = open("rogers.txt","r") if fn=-1 then fn = open("rogers.txt","w") puts(fn,text) close(fn) fn = open("rogers.txt","r") end if text = substitute(get_text(fn),"\r\n","\n") close(fn) end if sequence lines = split(text,"\n",false) printf(1,"%s\n",{join(reverse(lines),"\n")})
Obviously you can test the file handling by running the above, then changing eg Diplomacy to Diplomaxy and re-running it, and checking it outputs the previously saved c rather than the replacement x.
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Python
Interactive program which takes input from a file : <lang python>
- Aamrun, 4th October 2021
import sys
if len(sys.argv)!=2:
print("Usage : python " + sys.argv[0] + " <filename>") exit()
dataFile = open(sys.argv[1],"r")
fileData = dataFile.read().split('\n')
dataFile.close()
[print(i) for i in fileData[::-1]] </lang> Input file :
"Diplomacy is the art of saying 'Nice Doggy' until you can find a rock." --- Will Rodgers
Sample run and output:
- Output:
C:\My Projects\BGI>python rosetta7.py diplomaticQuote.txt --- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of C:\My Projects\BGI>
R
<lang R>text <- scan("Rodgers.txt", character(), sep = "\n") print(text) reversed <- rev(text) print(reversed) write(reversed, "SaveTheOutput.txt")</lang>
- Output:
Read 5 items [1] " \"Diplomacy is the art of" [2] " saying 'Nice Doggy'" [3] "until you can find a rock.\"" [4] " " [5] " --- Will Rodgers" [1] " --- Will Rodgers" [2] " " [3] "until you can find a rock.\"" [4] " saying 'Nice Doggy'" [5] " \"Diplomacy is the art of"
Raku
Not going to bother testing with the task recommended file. It demonstrates nothing to do with file handling, record separators, memory conservation or anything useful. May as well just be "Reverse this list" for all the good it does.
Lots of assumptions
Simplest thing that could possibly satisfy the extremely vague task description and completely glossing over all of the questions raised on the discussion page.
ASSUMPTIONS:
- File is redirected into STDIN from command line.
- Is a Unix or Windows format text file.
- Is in UTF8 encoding or some subset thereof.
- May hold entire file in memory.
<lang perl6>.put for reverse lines</lang>
Few assumptions
Processes a small (configurable) number of bytes at a time so file can be multi-terabyte and it will handle with ease. Does assume Latin 1 for reduced complexity.
No assumptions were made concerning line/record termination, full stop.
Run the following to generate nul.txt. (digits 1 through 6 repeated 8 times with double null as record separators):
raku -e'print join "\x00\x00", (1..6).map: * x 8' > nul.txt
<lang perl6>my $input-record-separator = "\x00\x00";
my $fh = open("nul.txt".IO, :r, :bin); $fh.seek(0, SeekFromEnd); # start at the end of the file
my $bytes = 5 min $fh.tell - 1; # read in file 5 bytes at a time (or whatever)
$fh.seek(-$bytes, SeekFromCurrent);
my $buffer = $fh.read($bytes).decode('Latin1'); # assume Latin1 for reduced complexity
loop {
my $seek = ($fh.tell < $bytes * 2) ?? -$fh.tell !! -$bytes * 2; $fh.seek($seek, SeekFromCurrent); $buffer = $buffer R~ $fh.read((-$seek - $bytes) max 0).decode('Latin1'); if $buffer.contains: $input-record-separator { my @rest; ($buffer, @rest) = $buffer.split: $input-record-separator; .say for reverse @rest; # emit any full records that have been processed } last if $fh.tell < $bytes;
}
say $buffer; # emit any remaining record</lang>
- Output:
66666666 55555555 44444444 33333333 22222222 11111111
REXX
version 1
This will work for all REXXes, but it reads all the file's lines/records into memory (storage or buffers).
No assumptions were made concerning line/record termination, as REXX takes care of that. <lang rexx>/*REXX pgm reads a file, and displays the lines (records) of the file in reverse order. */ parse arg iFID . /*obtain optional argument from the CL.*/ if iFID== | iFID=="," then iFID='REVERSEF.TXT' /*Not specified? Then use the default.*/ call lineout iFID /*close file, good programming practice*/
do #=1 while lines(iFID)>0 /*read the file, one record at a time. */ @.#= linein(iFID) /*assign contents of a record to array.*/ end /*#*/
recs= # - 1 /*# will be 1 more ('cause of DO loop)*/
do k=recs by -1 for recs /*process array (@.k) in reverse order.*/ say @.k /*display a record of the file ──► term*/ end /*k*/
call lineout iFID /*close file, good programming practice*/</lang>
- output when using the default input:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
version 2
This will work for all the following REXXes (and perhaps other REXXes as well):
- Regina REXX
- R4 REXX
- ROO REXX
- CMS REXX compiler
- CMS OREXX
<lang>/*REXX pgm reads a file, and displays the lines (records) of the file in reverse order. */ parse arg iFID . /*obtain optional argument from the CL.*/ if iFID== | iFID=="," then iFID='REVERSEF.TXT' /*Not specified? Then use the default.*/ call lineout iFID /*close file, good programming practice*/ options nofast_lines_BIF_default /*an option just for Regina REXX. */
- = lines(iFID) /*#: the number of lines in the file. */
do j=# by -1 for # /*read file (backwards), from bot──►top*/ say linein(iFID, j) /*display record contents ──► terminal.*/ end /*j*/
call lineout iFID /*close file, good programming practice*/</lang>
- output is identical to the 1st REXX version.
Ring
<lang ring> load "stdlib.ring" see "working..." + nl see "Input file lines:" + nl
fp = fopen("..\New\text.txt","r") r = "" txt = "" while isstring(r)
r = fgetc(fp) if r = -1 loop ok if r = char(10) txt += nl else txt += r ok
end
see txt + nl see "Reversed file lines: " + nl txt = str2list(txt) txt = reverse(txt) txt = list2str(txt) see txt fclose(fp)
see nl + "done..." + nl </lang>
- Output:
working... Input file lines: "Diplomacy is the art of saying 'Nice Doggy' until you can find a rock." --- Will Rodgers Reversed file lines: --- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of done...
UNIX Shell
<lang bash>tac rodgers.txt</lang> Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
Notice that tac is cat in reverse order.
Wren
<lang ecmascript>import "/ioutil" for File, FileUtil
var fileName1 = "rodgers.txt" var fileName2 = "rodgers_reversed.txt"
// read lines from input file var lines = FileUtil.readLines(fileName1) // remove final blank line, if any, added by some editors if (lines[-1] == "") lines.removeAt(-1)
// write lines in reverse order to output file File.create(fileName2) { |file|
for (i in lines.count-1..1) file.writeBytes(lines[i] + FileUtil.lineBreak) file.writeBytes(lines[0])
} // print contents of output file to terminal System.print(File.read(fileName2))</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of
XPL0
Usage: rev <will.txt <lang XPL0>char Array(1000, 1000); \(tacky) int Line, Char, I; def LF=$0A, EOF=$1A; [Line:= 0; repeat I:= 0;
repeat Char:= ChIn(1); Array(Line, I):= Char; I:= I+1; until Char = LF or Char = EOF; Line:= Line+1;
until Char = EOF; for Line:= Line-2 downto 0 do
[I:= 0; repeat Char:= Array(Line, I); I:= I+1; ChOut(0, Char); until Char = LF; ];
]</lang>
- Output:
--- Will Rodgers until you can find a rock." saying 'Nice Doggy' "Diplomacy is the art of