jinnks has asked for the wisdom of the Perl Monks concerning the following question:

Every time the code picks up a new line in the file it prints a horizontal margin as follows (exact output from the file)
<br> ______________________________________________________________________ +_____________________________________________________________________ +____________________________<br> Farhan<br> Khalid<br> This <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> makes <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> any <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> difference <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> to <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> the script <br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> ______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> 18:31:42, Wed Aug 6, 2008<br>

But what i am looking for is the output to be generated as follows

______________________________________________________________________ +_____________________________________________________________________ +_________________________<br> Farhan<br> Khalid<br> This <br> makes <br> any <br> difference<br> to <br> the script<br> 18:31:42, Wed Aug 6, 2008<br> ______________________________________________________________________ +_____________________________________________________________________ +______________________________________

the code below please advise what changes need to be made
#!/usr/bin/perl -w use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); my $query= new CGI; my $filename= "testfile.txt"; my $value; my $fname; my $lname; my $textarea; my $delimiter_used="|"; my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my @weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun); my ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfW +eek, $dayOfYear, $daylightSavings) = localtime(); my $year = 1900 + $yearOffset; my $theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$m +onth] $dayOfMonth, $year"; sub Writing_to_file { my @input_to_file=@_; open (DAT, ">>$filename") || die ("no file exists"); print DAT join($delimiter_used, @input_to_file), "\n"; close(DAT); } sub display_on_browser { open (DAT, $filename) || die ("no file exists"); my @data_in_the_file=<DAT>; close(DAT); print "Content-type:text/html\n\n"; print "<html><head><title>Guestbook</title></head><body> +"; for my $line (@data_in_the_file) { my @fields = split(/\Q|\E/gm, $line); for my $field (@fields) { print "<br>$field"; } print "<br>___________________________________________ +_____________________________________________________________________ +____________________________________________________"; } print "<a href=http://guestbook.ds5403.dedicated.turbodns.co.uk/in +dex.html><h1>Back to Guestbook</a>"; print "</body></html>"; } $fname=$query->param('name'); $lname=$query->param('name1'); $textarea=$query->param('comments'); if ($fname eq "") { print "Content-type:text/html\n\n"; print "<html><head><title>Guestbook</title></head><body>"; print "<b>You have missed out your first name</b>"; print "<a href=http://guestbook.ds5403.dedicated.turbodns.co.u +k/index.html><h1>Back to Guestbook</a>"; print "</body></html>"; } elsif($lname eq "") { print "Content-type:text/html\n\n"; print "<html><head><title>Guestbook</title></head><body>"; print "<b>You have missed out your last name</b>"; print "<a href=http://guestbook.ds5403.dedicated.turbodns.co.u +k/index.html><h1>Back to Guestbook</a>"; print "</body></html>";} elsif($textarea eq "") { print "Content-type:text/html\n\n"; print "<html><head><title>Guestbook</title></head><body>"; print "<b>You have missed out your comments</b>"; print "<a href=http://guestbook.ds5403.dedicated.turbodns.co.u +k/index.html><h1>Back to Guestbook</a>"; print "</body></html>";} else { Writing_to_file($fname,$lname,$textarea,$theTime); display_on_browser(); }

20080807 Janitored by Corion: Put output into code tags so it doesn't wide the page

Replies are listed 'Best First'.
Re: Problem with a new line
by toolic (Bishop) on Aug 06, 2008 at 18:38 UTC
    A side note: instead of repeating the same character (the underscore) 100 or so times, you could use the "x" repetition operator from Multiplicative Operators. These 2 lines are the same:
    print '<br>____________________', "\n"; print '<br>', '_' x 20, "\n";

    Feel free to update your post with fewer underscores because it renders very wide.

Re: Problem with a new line
by starX (Chaplain) on Aug 06, 2008 at 18:47 UTC
    I did get a warning when trying to run your script, but replacing my @fields = split(/\Q|\E/gm, $line); with my @fields = split(/\Q|\E/, $line); took care of that. I don't see where that change would be the cause of the problem you describe.

    Otherwise, as far as I can tell, you're script works as you think it should. However I was running it off the command line, which leads me to think that the problem lies somewhere in your html, or in the data that you're sending to the script. You might not only try chomping that data, but also using a regex to filter out anything except letters, numbers, and whitespace.

      if you try it on the server i am running on you will get the hang of what i am trying to say, as long as the data is submitted as a single line in the textarea it prints out fine with the '_' break in between but as soon as you enter the text in 2 lines or more it adds '_' breaks in between every entry in the text area. Please feel free to try it your self on http://guestbook.ds5403.dedicated.turbodns.co.uk/index.html thanks for you advice though it was a real help
        Aha. If that's the case, there are a couple things to try. First, stick a WRAP=SOFT within the opening TEXTAREA tag. Second, as I suggested before, use a regex to filter out those new lines. Super simplistic example:
        my $string = "this is \n a string with \n internal newlines."; $string =~ s/\n//g;
Re: Problem with a new line
by TGI (Parson) on Aug 07, 2008 at 01:21 UTC

    jinnks, I've rewritten your code and made a number of changes. While I am no Great God of Perl, I've learned a thing or two over the years. I suggest you study my changes and see if you can understand them.

    I've added a bunch of didactic comments aimed at explaining why I made the changes I made and what I am doing. You'll want to look at map, [perdoc://reftut], and perldsc.

    Comments in the code also discuss how the problem you are having is related to how you are serializing your data and offer some suggestions for fixing the problem.

    I hope all this helps you out. I used to point people at Ovid's cgi course, but the link is dead. You might be able to get it from the wayback machine.

    #!/usr/bin/perl # Don't use the -w switch. Use the warnings pragma. That way you can + disable it where needed. use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); my $query = new CGI; use constant DATA_FILE => 'testfile.txt'; use constant DELIMITER => '|'; # I cleaned up all the stuff at the front and jump right into the scri +pt. my ( $input, $errors ) = Process_Input($query); if (@$errors) { Display_Error_Page($errors); } else { Store_Data( $input->{name}, $input->{name1}, $input->{comments}, Format_Date_Time(), ); my $data = Load_Data(); Display_Main_Page($data); } exit; # not strictly necessary, but the exit communicates that # we are at the end of application logic rather nicely. # This replaces part of the big if/elsif/block. # We build up a list of bad fields in @errors. # Also, accepted field data from the query are stored in a hash. sub Process_Input { my $q = shift; my %input; my @errors; foreach my $field (qw(name name1 comments)) { my $value = $query->param($field); if ( defined $value and length $value ) { $input{$field} = $value; } else { $input{$field} = undef; push @errors, $field; } } return \%input, \@errors; } # A very simple routine to reduce some repeated code. # It could be extended by adding named arguments with # sensible defaults: # * content_type => content type to use. # * title => title of page # * heading => heading to put at top of page # * footer => stuff to display at bottom of page # * body => a string or array ref of stuff to put between # the heading and the footer. # Or you could move up to a proper templating system. # sub Print_Page { print "Content-type:text/html\n\n"; print join "\n", @_; return; } # Renamed from Writing_to_file for these reasons: # * Data store may not always be a file. # * The name was grammatically weird (I don't know the correct term, s +orry). # Write_To_File would have been better, but see the first reason. # # Fixed open() statement. # Used 3 argument open # Used lexical filehandle. # Reformatted the 'or die' clause. # Used low precedence 'or'. # Fixed error message and included $! to get real error. # # Consider making the file path the first argument of this routine. G +ets rid # of a global--it's a constant, but still it's a global. sub Store_Data { my @input_to_file = @_; open( my $data, '>>', DATA_FILE ) or die "Error opening file: $!"; # This is the source of your problem. # The serialization you are using does not escape '\n', and so ent +ries # with line breaks are treated at separate one field entries. # # One solution would be to fix your serialization routine to escap +e # '\n' and '|' and also make sure that whatever you use to mark yo +ur # escapes is also escaped. For example, if you use '\', to escape + '|' so # that '|' becomes '\|', and use '\n' for new lines, the you'll al +so need # to escape '\' as '\\'. # # The other option would be to use a library to serialize your dat +a. # Text::CSV, a db file, YAML, or DBD::SQLite would all be good opt +ions. print $data join( DELIMITER, @input_to_file ), "\n"; close($data); } # Fixed the case of the routine name to be consistent. # Changed name to Display_Main_Page, because it may be going to anythi +ng, not # just a browser. # # This routine requires a reference to a two dimension array for its a +rgument. # sub Display_Main_Page { my $data = shift; Print_Page( "<html><head><title>Guestbook</title></head><body>", map( Format_Data_Row($_), @$data ), "<a href=http://guestbook.ds5403.dedicated.turbodns.co.uk/inde +x.html><h1>Back to Guestbook</a>", "</body></html>", ); return; } # Build a two-dimensional array of data # and return a reference to it. # Result looks like: # my $data = [ # [ 'Bob', 'Smith', 'foo bar baz', '12:12:23 Wed Aug 6, 2008' ], # [ 'John', 'Smith', 'foo bar baz', '22:42:23 Wed Aug 6, 2008' ], # ]; # # Consider making the file path the first argument of this routine. G +ets rid # of a global--it's a constant, but still it's a global. sub Load_Data { open( my $data, '<', DATA_FILE ) or die "Error opening file: $!"; my @data_from_file = map Process_Data_Line($_), <$data>; close($data); return \@data_from_file; } # Process one line of data into an array ref sub Process_Data_Line { my $line = shift; chomp $line; # clean up those pesky line ends. # Your original regex used a hard coded '|' for the delimeter. If + someone # changed the $delimeter variable at the top of the file, you'd ha +ve an # instant bug. Consistency is key, if you are going to use config +uration # constants (which is a good idea), use them everywhere. # # The need muck about with an intermediary string to form my regex + is one # thing that sucks about use constant. # # There is all sorts of discussion about the relative merits of co +nstant # vs. Readonly and the other options. Much of it in relation to t +he # recommendation in PBP to use Readonly. Search around on perlmon +ks and # you'll find it. my $split_regex = '[' . DELIMITER . ']'; my @fields = split( /$split_regex/, $line ); return \@fields; } # Format a row of data from your data array. sub Format_Data_Row { my $row = shift || []; my $formatted_text = join '<br>', '', # Get leading <br> @$row, '_' x 100, # Big delimiter, why not +an <hr>? ''; # Add a trailing <br> return $formatted_text; } # All the cluttery date time formatting stuff is now in a sub where it + can be # ignored until you decide to use a library like DateTime to do your d +irty # work. # # Made all your variable names use a consistent style: # lower_case_names_with_underscores sub Format_Date_Time { my $time = shift || time; my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec +); my @week_days = qw(Sun Mon Tue Wed Thu Fri Sat Sun); my ($second, $minute, $hour, $day_of_month, $month, $year_offset, $day_of_week, $day_of_year, $daylight_savings ) = localtime($time); my $year = 1900 + $year_offset; my $the_time = "$hour:$minute:$second, $week_days[$day_of_week] $months[$mo +nth] $day_of_month, $year"; return $the_time; } # This replaces the rest of the big if/elsif block. # This version will display all missing fields in the error page. sub Display_Error_Page { my $errors = shift; my %field_description = ( name => 'first name', name1 => 'last name', comments => 'comments', ); my $missing_fields = join ", ", map { $field_description{$_} } @$e +rrors; Print_Page( "<html><head><title>Guestbook</title></head><body>", "<b>You have missed some required fields: $missing_fields</b>" +, "<a href=http://guestbook.ds5403.dedicated.turbodns.co.uk/inde +x.html><h1>Back to Guestbook</a>", "</body></html>", ); return; }


    TGI says moo

      This makes much more sense i will have to study the code a lot more to understand it fully which is my next move thanks for the explanation :)
Re: Problem with a new line
by spivey49 (Monk) on Aug 06, 2008 at 18:25 UTC

    You can use chomp to remove the new lines from your input

Re: Problem with a new line
by Cristoforo (Curate) on Aug 06, 2008 at 19:53 UTC
        Oops, sorry jinnks, I now see that you are printing the horizontal line in the outer loop. I can't see why its printing the way you describe. Perhaps I can make up some data to see if I can find out why.

        I guess you can not use just any module (like POSIX) since it probably depends on the service that you are using. And besides, your date code works perfectly well.

        Sorry about that.

    Re: Problem with a new line
    by tptass (Sexton) on Aug 06, 2008 at 22:37 UTC

      What exactly does your text document look like with your guestbook entries? Does it look correct with the delimiter?

      Check out your for loop...

      for my $line (@data_in_the_file) { my @fields = split(/\Q|\E/gm, $line); for my $field (@fields) { print "<br>$field"; } print "<br>______"; }

      You loop through every line in the file in the outer loop so if one were to enter a new line in the comment then it would be an additional line, which would mean it would go through the inner code. You have to do a check to see if the line has a "|", your demlimiter and if it does than and only then print our your "
      ___". Example:

      for my $line (@data_in_the_file) { my @fields = split(/\Q|\E/gm, $line); for my $field (@fields) { print "<br>$field"; } print "<br>______" if ($line =~ m/\|/); }

      Update: Actually ran a test, I forgot you had to bash slash the delimiter. All you will have to do is add the following to the horizontal bar:

      if ($line =~ m/\|/);