Solved

How to add lines into text file

Posted on 2009-07-14
4
200 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
4 Comments
 
LVL 39

Accepted Solution

by:
Adam314 earned 200 total points
ID: 24853560
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
ID: 24854004
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
ID: 24854310
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
ID: 31603429
thanks!
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
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…
Six Sigma Control Plans

617 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