Reverse the order of lines in a text file while preserving the contents of each line: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Algol W)
(→‎version 2: updated DO loop to not read the file's contents into an array, used a (temporary) internal work area.)
Line 352: Line 352:
if iFID=='' | iFID=="," then iFID='REVERSEF.TXT' /*Not specified? Then use the default.*/
if iFID=='' | iFID=="," then iFID='REVERSEF.TXT' /*Not specified? Then use the default.*/
call lineout iFID /*close file, good programming practice*/
call lineout iFID /*close file, good programming practice*/
options noFast_lines_BIF_default /*an option just for Regina REXX. */
options nofast_lines_BIF_default /*an option just for Regina REXX. */
#= lines(iFID) /*#: the number of lines in the file. */
#= lines(iFID) /*#: the number of lines in the file. */
do j=# by -1 for # /*read file (backwards), from bot──►top*/
do j=# by -1 for # /*read file (backwards), from bot──►top*/
@.j= linein(iFID, j) /*assign contents of a record to array.*/
say linein(iFID, j) /*display record contents ──► terminal.*/
say @.j /*display a record of the file ──► term*/
end /*j*/
end /*j*/
call lineout iFID /*close file, good programming practice*/</lang>
call lineout iFID /*close file, good programming practice*/</lang>

Revision as of 17:22, 7 August 2021

Reverse the order of lines in a text file while preserving the contents of each line is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
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.


For the input file, use the following five lines (records):

 "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

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

Factor

Works with: Factor version 0.99 2021-06-02

<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

Translation of: Wren

<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

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

Works with: Free Pascal

maybe

Works with: Delphi

<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 = get_text(fn)
    close(fn)
end if
sequence lines = split(text,"\n",false)
puts(1,join(reverse(lines),"\n"))
Output:
                            --- Will Rodgers

until you can find a rock."
   saying  'Nice Doggy'
 "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. */

  1. = 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

Works with: Bourne Again 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

Library: Wren-ioutil

<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