469,314 Members | 2,106 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,314 developers. It's quick & easy.

How does textarea define newline? (perl)

what's going on?

text entered into an HTML textarea input:

field1=1
field2=2
field3=3

this data gets stored in a text file:

Expand|Select|Wrap|Line Numbers
  1. my $data = getParam("data"); # a simple sub which grabs param data from a URL
  2. open F, ">data.txt";
  3. print F $data;
  4. close F;
  5.  
i then, later, read this data into an array, removing the field names and = sign.

Expand|Select|Wrap|Line Numbers
  1. my @data = (); # an array to store the data
  2. my $i = 0; # @data array index
  3. open F, "<data.txt";
  4. while (my $d = <F>) {
  5.   $d =~ s/\n//g; # remove any and all \n's from this line
  6.   $d =~ s/(.)*=//; # remove all chars up to and including the = sign
  7.   @data[$i] = $d; # add to the array $d;
  8.   $i++; # increment the index
  9. }
  10. close F;
  11.  
seems element 0 in the array gets the value of 2, not 1 as expected...

and here is the code for the getParam sub:

Expand|Select|Wrap|Line Numbers
  1. use CGI;
  2.  
  3. sub getParam {
  4.   my $rv = (new CGI)->param($_[0]);
  5.   $rv =~ s/\n//;
  6.   return $rv;
  7. }
  8.  
Nov 1 '14 #1
15 13106
RonB
589 Expert Mod 512MB
When posting questions like this, it's best to post a short but complete script and html code that demonstrates the issue so that we can run it without having to make up our own code which may not match your situation.

I will need to run a test but the issue you're seeing may be due to the difference between Windows (\r\n) and unix (\n) line endings. You can use the *nix od command to view and verify the line endings.

It's also a good idea to use the Data::Dumper module to see what a var contains.

Are you really writing to and reading from data.txt in the same script? If so, that doesn't make mush sense and is a very awkward way to handle the form submission data.

Your getParam() sub is also an odd and inefficient approach.

Here are some of the issues with your code.
1) Using bareword filehandles
2) Using 2 arg instead of 3 arg form of the open call
3) No error handling on the open calls
4) Using @ instead of $ when referencing array element
5) Failure to use push when it's more appropriate
Nov 1 '14 #2
RonB
589 Expert Mod 512MB
The problem is with your subroutine. It's dropping the first row (field1).

I'm looking over it now to find out why and the fix, but you really should drop that sub and use the methods provided by the CGI module.
Nov 1 '14 #3
RonB
589 Expert Mod 512MB
You have 2 items that is causing this problem.

1) The regex in the getParam() sub is combining the first to fields/lines into one line.

2) Your s/(.)*=//; regex in the while loop is greedy and due to that it's stripping everything upto to last = equals sign leaving you with the 2.

Proper use of chomp, split and push instead of any of those regexs would be the proper solution, but if you want to keep them, drop the one in the sub and adjust the one in the while loop to this:
Expand|Select|Wrap|Line Numbers
  1. $d =~ s/(.+?)=//;
Nov 1 '14 #4
RonB
589 Expert Mod 512MB
Expand|Select|Wrap|Line Numbers
  1. <html>
  2. <head></head>
  3. <body>
  4.   <form action="/cgi-bin/jamroll.pl" method="get">
  5.     <textarea rows="4" col="25" value="" name="data"></textarea>
  6.     <input type="submit" name="Submit">
  7.   </form>
  8. </body>
  9. </html>
Expand|Select|Wrap|Line Numbers
  1. use strict;
  2. use warnings;
  3. use CGI;
  4. use CGI::Carp qw(fatalsToBrowser);
  5. use Data::Dumper;
  6.  
  7. my $cgi    = CGI->new;
  8. my %params = $cgi->Vars;
  9. my @data   = split /\r\n/, $params{'data'};
  10.  
  11. # \r in the split was needed because
  12. # I did this on Windows
  13.  
  14. s/^.+?=// for @data;
  15.  
  16. die Dumper \@data;
  17.  
Outputs:
Expand|Select|Wrap|Line Numbers
  1. $VAR1 = [
  2.           '1',
  3.           '2',
  4.           '3'
  5.         ];
Nov 1 '14 #5
Hi RonB!

so very happy to see your comments. i thought i had made a workable script to reproduce the error, my bad.

I did not realize my regex was greedy....a +? will make it non-greedy? i've been doing perl for a few years now - i think i have gotten pretty darn good with it. but, honestly i have not come across +?. intriguing...

As for if i am reading and writing data.txt in the same script. no, to be succinct. yes and no to be less succinct.

i have an "admin" section to my site, which allows me to edit data.txt, and in its most basic form it creates an html page (if no params are supplied), otherwise, it writes the data.txt file. i think this to be efficient. that's the admin side. user side cannot edit the data.txt file - they can only use it. data.txt is a group of fields (the first field is to be a name like red, or blue) and the remaining fields define colours. not really relevant to the issue.

i'm sorry i didn't get back to this quicker. I stayed on this page for literally hours. watched the view count go from 1 to 96 before I passed out on the couch. only JUST woke up (sippin first cup of coffee now - haven't even had my morning smoke, that's how important this is).

hoping my site will generate a decent income when completed and live.
Nov 1 '14 #6
RonB
589 Expert Mod 512MB
If you're in the design phase of the app, don't make the mistake of designing it around the CGI module. Don't get me wrong, it's a good module but outdated and now is generally used as beginning level teaching aide. You should be using one of the MVC frameworks. I just started using Dancer2 and it makes web design a breeze when compared to the CGI module route.
Nov 1 '14 #7
oh, i forgot to address the getParam function.

the following is a condensed version of misc.pm (it contains MANY more subs. I have removed those subs, and only show the getParam sub (superfluous code removed for brevity's sake).

Expand|Select|Wrap|Line Numbers
  1. package misc;
  2.  
  3. use strict;
  4. use CGI::Carp qw(fatalsToBrowser);
  5. use CGI;
  6.  
  7. $VERSION     = 1.00;
  8. @ISA         = qw(Exporter);
  9. @EXPORT      = qw(getParam);
  10.  
  11. ###################
  12. sub getParam {
  13.   my $rv = (new CGI)->param($_[0]);
  14.   $rv =~ s/\n//;
  15.   # $rv =~ s/\r//;
  16.   return $rv;
  17. }
  18.  
not sure why this sub is "odd"...seems rather efficient, and I don't have to continually write the code in getParam throughout my site....that's prone to errors.

as for bareword filehandles...i've only seen it done this way. can you suggest the proper way??

open F, "<data.txt" is 2 args, yes. what more do i need?

i don't do any error handling in this because that gets done WAY before the call to open.

does it really matter if i use $ instead of @??

i know of the push function....i guess i could use it. not really sure why i haven't, honestly. i ought to fix that.

i will update my regex's to reflect the changes you suggest.
Nov 1 '14 #8
RonB
589 Expert Mod 512MB
6 problems with your getParam() sub
1) Uses indirect object notation
2) Needlessly creates a new object every time it's called
3) Needles use of method chaining
4) Can only deal with 1 param at a time
5) The purpose of the regex is ambiguous
a) is the intension to remove the first \n character
b) is the intension to remove the ending \n character
b) is the intension to remove all \n characters
6) In a multi-line field, the regex will combine the first 2 lines, which in this case (and most cases) is not what you want

That sub could/should be replaced with a single line of code that calls the CGI method that returns ALL of the form fields. That should be done very near to the beginning of the script. My example script does just that.

Bareword filehandles are global and are stored as part of the system table and can clash with uses of that same handle in other areas of the script. You should be using a lexical var for the handle in the smallest scope it requires. Another benefit of lexical handles is that they automatically close when they go out of scope.

The 2 arg form has security holes that can allow a hacker to take advantage of and cause problems. Here's an example of the more secure 3 arg form (without the proper error handling).
Expand|Select|Wrap|Line Numbers
  1. open my $fh, '<', 'data.txt';
Error checking/handling should be done in EVERY open call to make sure it was successful.

c:\test>perl -Mdiagnostics -e "@data[0] = 'bad';"
Scalar value @data[0] better written as $data[0] at -e line 1 (#1)
(W syntax) You've used an array slice (indicated by @) to select a
single element of an array. Generally it's better to ask for a scalar
value (indicated by $). The difference is that $foo[&bar] always
behaves like a scalar, both when assigning to it and when evaluating its
argument, while @foo[&bar] behaves like a list when you assign to it,
and provides a list context to its subscript, which can do weird things
if you're expecting only one subscript.

On the other hand, if you were actually hoping to treat the array
element as a list, you need to look into how references work, because
Perl will not magically convert between scalars and lists for you. See
perlref.
EDIT
If you use the autodie pragma, you don't need to include the error handling on the open calls because the pragma will do it for you.
Nov 1 '14 #9
RonB
589 Expert Mod 512MB
Since you appear to like retrieving the params one at a time, why not simply use the param() function from CGI's functional interface?
(i.e., use CGI ':standard';)
Expand|Select|Wrap|Line Numbers
  1. my $data = param('data');
  2.  
  3. # or the OO method
  4. my $cgi = CGI->new;
  5. my $data = $cgi->param('data');
That's one line just like calling your sub, but it's more efficient.
Nov 1 '14 #10
ok. this is going to take me a while to write up (i proof read lots, correct errors, and reword to make sure i get my message across exactly the way i need it to be).

apologies for not getting back to you until now. i've been with my sons all day today. currently, it's 1am, my time.

your words are rather humbling, and i feel intermediate, at best. believe it or not, though, i AM glad for this! thank you, kind sir!

i don't want to usurp your time, but ... clearly i lack knowledge (of terminology and syntax):

$foo[&bar] ? what's the &bar doin in there? isn't that a subroutine? :s
or is & a variable type like $? no, right? i've done tons of programming in my life. i really enjoy perl coding - it's fun as carnivals. but, perl seems....odd somehow.

does @foo[0] return different data than $foo[0] ? or, is it just sloppy somehow? if so, how? is $foo[$i] 'bad'?

are these all the same var?
@data
$data
&data

how do i make a filehandle lexical? like this? i read somewhere this was how to make things lexical:
Expand|Select|Wrap|Line Numbers
  1. {
  2.   if open F, "<", "data.txt" {
  3.     close F;
  4.   } else {
  5.     print "<b>eek!</b>  opening data.txt for reading failed: $!<br>\n";
  6.   }
  7. }
  8.  
i see what yer sayin about the getparam function. it'll get deprecated shortly. i just wanted to shorten the length of that command. $cgi->param('data') is much harder to type than getparam('data');

gosh. no clue what "at -e line 1 (#1) (W syntax)" means. blink blink

i check if files exist prior to nearly all open commands. so i can redirect, or display errors messages. i try to do most error checks before getting into the "meat" of the code.

in some cases, i do this, instead of die (die is kinda ugly):
Expand|Select|Wrap|Line Numbers
  1. if (open F, '<', "data.txt") {
  2.   #
  3.   # success code here
  4.   #
  5.   close F:
  6. } else {
  7.   #
  8.   # display error msg with $!
  9.   #
  10. }
  11.  
looks nicer, and allows me to control the output of the error msg, whereas die just kills the whole works, and its output (although very useful) is ... abrupt, and lacks aesthetics.

also, inserting the above code into an already two or three layer nested if structure is cumbersome, is prone to bugs, and can get confusing. so i do my best to check before hand and make my error messages look better, instead of looking like it was interrupted due to bad coding (from a user perspective; this might make them feel uneasy about the site).

i don't like that i can't declare an array size (eg: my @array[0..23];) like you can in most other languages. well, i guess i could. my $array = ['', '', '', ''.......]; but that seems awful somehow. I guess i'm just not sure when to use $ or @.

Dancer2? MVC Framwork? arrooo?? i only use CGI sparingly. just for the params thing. i have no ideas on how to use CGI further than that in my scripts. probably won't need to.

i've come across pragma before. never really looked into it...is it critical i learn that here?

um, what else? oh ya! i want to remove ALL occurences of \n (and/or \r). this way, regex matching elsewhere works. also, i don't want to have \n or \r in $filename or in an array element, for instance. and, what if it's not \r\n but \n\r ?? lol. i tend to remove one, then the other.

you see, i'm pretty particular how my data is stored, and retrieved. i need to make sure it's all formatted basically the same. if not, odd things can happen in the HTML output. i don't use those functions which do HTML for me. I hand code that part myself. i incorporate pretty printing into the html output. a random \n can wreak havoc in the wrong place (not just for the pretty printing, but it can SOMETIMES break the HTML, too).

not sure why i haven't used push. why is it more appropriate than the way i add elements to an array? most of my arrays are small, and just plain text. nothing too complicated about them. i haven't even delved into hashes yet. well, i've dipped my toe, so to speak. read some things. kinda neat. might work nice for storing info from my data.txt files.

i've got some learning, and a bunch of recoding to do.

thanks again, Ron, for your time, and expertise!

it's now almost 230. got that done faster than i thought.
Nov 2 '14 #11
oh oh. the data.txt file!

each line will need the \n put back before writing to data.txt:

print F "$data_element\n";

so the data file, in notepad would look like what you typed in the textarea. i'm sure textarea is messing with me somehow. could it be that \r. i'm running ubuntu here. the server i am using is owned/operated (whatever) by x10hosting.com which are *nix servers, of course.
Nov 2 '14 #12
RonB
589 Expert Mod 512MB
I now see why you didn't know/understand some of the things I said.

When you said that you've been using perl for a few years, I assumed that you had more knowledge in it than you actually have. You appear to lack a good or basic understanding of some of the fundamentals.

$foo[&bar] ? what's the &bar doin in there? isn't that a subroutine?
Yes, & is the sigil for a subroutine. &bar is a subroutine call and when used as part of $foo[$bar] the implication is that it returns an integer which is used for the index into the @foo array.

If @ was used instead of $ then it changes the context and implies that &bar should return a list of integers for the indexes and means you're now working with an array slice which may or may not have been what was intended. i.e., it could be a bug in the code.

are these all the same var?
@data
$data
&data
No, they are not the same. @data is an array and $data is a scalar which are a completely different vars. &data is a subroutine, not a var.

Knowing the difference between the $, @, %, &, and * sigils and knowing when to use each is considered a very basic perl fundamental.

how do i make a filehandle lexical?
The my keyword is used to declare a lexical var and the our keyword is used to declare a global var which is rarely used.
Expand|Select|Wrap|Line Numbers
  1. open my $filehandle, 'data.txt';
  2.  
Coping with Scoping

i see what yer sayin about the getparam function. it'll get deprecated shortly. i just wanted to shorten the length of that command. $cgi->param('data') is much harder to type than getparam('data');
I personally prefer to use that OO interface, but you could use the functional interface which is shorter syntax than calling your sub, which is a wrapper to the OO call (that's a total of 3 subroutine calls).
Expand|Select|Wrap|Line Numbers
  1. my $data = param('data');
  2.  
i check if files exist prior to nearly all open commands. so i can redirect, or display errors messages. i try to do most error checks before getting into the "meat" of the code.

in some cases, i do this, instead of die (die is kinda ugly):
Checking for existence prior to open call is fine, BUT that doesn't mean that the open call will be successful. There are a number of reasons it could fail other than not existing.

In web programming, die is almost never used. I only use it in specific cases of debugging like the example I posted earlier.

Here's a common approach I use in web app errors.
Expand|Select|Wrap|Line Numbers
  1. open my $fh, '<', $data_file or display_error_page('some appropriate error message');
  2.  
  3. # If we got here, open call was good
  4. while (my $line = <$fh>) {
  5.   # process $line
  6. }
i don't like that i can't declare an array size (eg: my @array[0..23];) like you can in most other languages.
You can declare an array with a specific size by doing an assignment, however, there really isn't any good reason to do so.
Expand|Select|Wrap|Line Numbers
  1. my @data = (undef) x 20;
I'm running late, so the rest of my comments will have to wait.
Nov 2 '14 #13
i was just making sure i understood $, @, &, etc correctly, and turns out i do. i got confused cuz i hadn't used a function as an element index, that's all...

filehandles:
ok. "open my $fh" from now on when i open files, instead of "open FH". tyvm for that.
also, i have fixed all open statements to use the 3 arg format instead of the 2 arg format. tyvm for that, too! :D

i will no longer use my homebrewed "&getParam()" sub, but will leave it in (cuz that will break other projects). it's in a module, but no matter. i made a new var at the top of the module (my $cgi = new CGI;), and &getParam will use it, if called. i am in the process of changing all &getParam() calls to just &param() calls

i appreciate the time you are taking to help me out! truly and sincerely, thank you very much!
Nov 3 '14 #14
RonB
589 Expert Mod 512MB
Don't use the & when calling/executing subs, unless you know about and understand and need the side effects it causes.
Nov 3 '14 #15
ok. i won't. and don't.

thanks again, Ron! :D This page is bookmarked.
Nov 3 '14 #16

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

6 posts views Thread by Alessandro Crugnola *sephiroth* | last post: by
8 posts views Thread by Sandy Tipper | last post: by
1 post views Thread by jschenker01 | last post: by
reply views Thread by harlem98 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.