Solved

How to add lines into text file

Posted on 2009-07-14
4
196 Views
Last Modified: 2012-05-07
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

0
Comment
Question by:ommer
  • 2
  • 2
4 Comments
 
LVL 39

Accepted Solution

by:
Adam314 earned 200 total points
Comment Utility
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
 

Author Comment

by:ommer
Comment Utility
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
 
LVL 39

Expert Comment

by:Adam314
Comment Utility
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
 

Author Closing Comment

by:ommer
Comment Utility
thanks!
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
There are many situations when we need to display the data in sorted order. For example: Student details by name or by rank or by total marks etc. If you are working on data driven based projects then you will use sorting techniques very frequently.…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This video discusses moving either the default database or any database to a new volume.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now