How to add lines into text file

Hi, all,
I tried to insert lines and text strings into a text file using Tie::File, but had run into several obstacles. Your help is greatly appreciated!
1) the splice line of my code has caused "bad file descriptor error on my ../Tie/File.pm
2) I had hard time to find a solution that will find the dynamic line number for the seesion footer, i.e. the "Subtotal"s, which should be the next line after the  50/51...runs.
To describe the steps involved:
1) based on the first two numbers of the 2nd column, if = 50, then Salaries, if =51 then Operating...
2) insert a line before the 50 session with the label of 'Salaries' or 'Operating'... and
3) add a label on the session footer line as subtotal...
Btw, I have full control of the creation of the input file. In another words, I could make it comma delimited or tab delimited or fixed position, so the regular expression could find them.
Also, since the file is likely smaller than 1 mg, and the script will only be called occassionaly, I don't mind to have a solution that doesn't use Tie::File.

Here is the simplified input file
-----  ------ -----
xyz    50100   $100
yyy    50200  $1000
zzz    50300
                   $1100    
abc    51200  
bbbb   51300  $123
                   $123

and here is the output/modified file
-----  ------ -----
Salaries                               #<--inserted session header line
xyz    50100   $100
yyy    50200  $1000
zzz    50300      
  Subtotal Salaries $1100  #<--insterted session footer label
Operating                          #<--inserted session header line
abc    51200  
bbbb   51300  $123
  Subtotal operating $123 #<--insterted session footer label

use Tie::File;
tie(@lines, 'Tie::File', $myfile) or die "Could not open $myfile: $!\n";
if($#lines == -1) {
    print "File is empty!\n";
}
else {
   if (substr($_,5,2  =='50' ){
          my $new_line ="Salaries";
          splice @lines, $.+1, 0, $new_line; }
    elseif(substr($_,5,2  =='51' ){
          my $new_line ="Operating";
          splice @lines, $.+1, 0, $new_line; }<--then insert a line above it
         <--then add the same label to the end of the session
}
print $_."\n";   
 }

Open in new window

ommerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Adam314Commented:
Call by giving the input and output filenames on the command line.

eg:  script.pl input.txt output.txt

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
 
die "Usage: $0 <input> <output>\n" unless $#ARGV==1;
my $input = shift;
my $output = shift;
 
open(my $in, "<$input") or die "Could not open '$input': $!\n";
open(my $out, ">$output") or die "Could not open '$output': $!\n";
 
my $state;
while(<$in>) {
	if(/\S+\s+(\d{2})/ and !defined($state)) {
		if($1 eq '50') {
			$state = 'Salaries';
		}
		elsif($1 eq '51') {
			$state = 'Operating';
		}
		print $out "$state\n";
	}
	elsif(/^\s+\$\d+\s*$/ and $state) {
		s/(.*)/  Subtotal $state $1/;
		$state = undef;
	}
	print $out $_;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ommerAuthor Commented:
Great! It works flawlessly against my test data.

However, could you give me a little more explanations on next two lines, so when I apply it to the production data, I can make right adjustments?

if(/\S+\s+(\d{2})/ and !defined($state))  

elsif(/^\s+\$\d+\s*$/ and $state)
0
Adam314Commented:
if(/\S+\s+(\d{2})/ and !defined($state))
If the line matches the pattern:
    \S+         1 or more non-whitespace characters
    \s+          1 or more whitespace
    (...)         Save what is in the parenthesis to the $1 variable
    \d{2}      2 digits
And the $state hasn't yet been defined (meaning, this is the first line of a new session)

elsif(/^\s+\$\d+\s*$/ and $state)
If the line matches the pattern:
    ^             start of line
    \s+          1 or more whitespace
    \$            A dollar sign.  The $ is a special character, the backslash mean an actual dollar sign
    \d+         1 or more digits
    \s*          0 or more whitespace
    $             end of line
And $state is set (meaning, the session header has been printed, it contains the session name)
0
ommerAuthor Commented:
thanks!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.