Solved

How to add lines into text file

Posted on 2009-07-14
4
197 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
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

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Perl Sort Question 4 135
remove duplicates from the csv file 13 108
How to search multiple patterms in a file with perl? 4 80
Control Number of Log Files -Perl 7 73
Many time we need to work with multiple files all together. If its windows system then we can use some GUI based editor to accomplish our task. But what if you are on putty or have only CLI(Command Line Interface) as an option to  edit your files. I…
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
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…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

778 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