Totally stuck

D

David Arnold

All,

I have a file named "new".

\backtomargin


In Exercises~\ref{exer2.9.1}--\ref{exer2.9.2}, if the given
differential equation is autonomous, identify the equilibrium
solution(s). Use a numerical solver to sketch the direction field
and superimpose the plot of the equilibrium solution(s) on the
direction field. Classify each equilibrium point as either
unstable or asymptotically stable.






\ex\label{exer2.9.1} $P'=0.05P-1000$

The spacing is intentional. Now, my perl file is saved as new.pl.

use strict;
use warnings;

# replace \backtomargin with instructions environment
my @instructions;
my $instruct_line;
while (my $line=<>) {
chomp($line);
if ($line=~/^\s*\\backtomargin/) {
push (@instructions,$');
while ($instruct_line=<>) {
chomp($instruct_line);
if ($instruct_line=~/\\ex/) {
last;
} else {
push(@instructions,$instruct_line);
}
}
print "\\begin{instructions}\n";
# remove blank lines from end of array
while($line=pop(@instructions)) {
if ($line=~/^\s*$/) {
print "true\n";;
} else {
print "false\n";
push (@instructions,$line);
last;
}
}
# remove blank lines from the beginning of the array
while($line=shift(@instructions)) {
if ($line=~/^\s+$/) {
;
} else {
unshift (@instructions,$line);
last;
}
}
print join("\n",@instructions);
# empty instructions array for next pass
@instructions=();

print "\\end{instructions}\n\n";
print "$instruct_line\n";

} else {
print "$line\n";
}
}

When I enter:

perl new.pl < new

I get the following output:

D:\NewBook\conversion>perl new.pl < new
\begin{instructions}

In Exercises~\ref{exer2.9.1}--\ref{exer2.9.2}, if the given
differential equation is autonomous, identify the equilibrium
solution(s). Use a numerical solver to sketch the direction field
and superimpose the plot of the equilibrium solution(s) on the
direction field. Classify each equilibrium point as either
unstable or asymptotically stable.




\end{instructions}

\ex\label{exer2.9.1} $P'=0.05P-1000$


I am using ActiveState Perl on Win95. You might note the debugging
print statements and the fact that neither "true" nor "false" shows up
in the output.

I am completely stuck and in need of kind pair of eyes. If you can
help, it would be appreciated.

Thanks.
 
G

gnari

The spacing is intentional. Now, my perl file is saved as new.pl.

# remove blank lines from end of array
while($line=pop(@instructions))
if ($line=~/^\s*$/) {
print "true\n";;
} else {
print "false\n";
push (@instructions,$line);
last;
}
}

I am using ActiveState Perl on Win95. You might note the debugging
print statements and the fact that neither "true" nor "false" shows up
in the output.

clearly the while() block is never executed, because
$line evaluates as false the first time through ('')

maybe you want something like
pop @instructions while $instructions[-1] =~ /^\s*$/;

gnari
 
A

Andrew Lee

All,

I have a file named "new".

\backtomargin


In Exercises~\ref{exer2.9.1}--\ref{exer2.9.2}, if the given
differential equation is autonomous, identify the equilibrium
solution(s). Use a numerical solver to sketch the direction field
and superimpose the plot of the equilibrium solution(s) on the
direction field. Classify each equilibrium point as either
unstable or asymptotically stable.






\ex\label{exer2.9.1} $P'=0.05P-1000$

The spacing is intentional. Now, my perl file is saved as new.pl.

use strict;
use warnings;

# replace \backtomargin with instructions environment
my @instructions;
my $instruct_line;
while (my $line=<>) {
chomp($line);
if ($line=~/^\s*\\backtomargin/) {

But there is no space before "\backtomargin" ... so the following lines never
get executed.
push (@instructions,$');
while ($instruct_line=<>) {
chomp($instruct_line);
if ($instruct_line=~/\\ex/) {
last;
} else {
push(@instructions,$instruct_line);
}
}


..snip

From what I can gather at a quick look, you are trying to nab everything between
"\backtomarin" and "\endofinstructions". Am I correct?

If so, try this :

if ($line=~/^\s+\\backtomargin/) {

and put whitespace before the delimeter "\backtomargin".

Better still, use a character or string that you don't expect to find elswhere
in the testfile, such as #.

Than you can say :

if ($line=~/^\#\\backtomargin/) {

.... etc.

HTH
 
T

thundergnat

Andrew said:
But there is no space before "\backtomargin" ... so the following lines never
get executed.

I don't know... It looks to me like there is zero or more spaces before
'\backtomargin'.



Actually, I think the logic problem is the lines:
while($line=pop(@instructions)) {
and
while($line=shift(@instructions)) {


Since the first line that gets popped off of the array is a blank line,
the while() short circuits and the code block never gets executed.


Seems to me you are doing an awful lot of extra work chomping off
newlines only to add them back in, and making arrays when you really
want strings. If I was trying to do something similar, I would probably
do something like:


use strict;
use warnings;

my $instructions;
my $instruct_line;

while (<>) {
if ($_ =~ s/^\s*\\backtomargin//) {
$instructions = $_;
while ($instruct_line=<>) {
last if ($instruct_line =~ /\\ex/);
$instructions .= $instruct_line;
}
$instructions =~ s/ *\n/\n/g;
while ($instructions =~ s/\n\n\n/\n\n/) {};
$instructions =~ s/^\n+//;
$instructions =~ s/\n{2,}$/\n/;
print
"\\begin{instructions}\n$instructions\\end{instructions}\n\n$instruct_line\n";
} else {
print "$_\n";
}
}



Not knowing what your exact formatting needs were, I took a guess based
on what it /looked/ what you were trying to do.
 
D

David Arnold

gnari,
clearly the while() block is never executed, because
$line evaluates as false the first time through ('')

maybe you want something like
pop @instructions while $instructions[-1] =~ /^\s*$/;


Thank you very much. Your suggestion pointed to the difficulty. I am
now using the following and all is working well.

use strict;
use warnings;

# replace \backtomargin with instructions environment
my @instructions;
my $instruct_line;
while (my $line=<>) {
chomp($line);
if ($line=~/^\s*\\backtomargin/) {
push (@instructions,$');
while ($instruct_line=<>) {
chomp($instruct_line);
if ($instruct_line=~/\\ex/) {
last;
} else {
push(@instructions,$instruct_line);
}
}
print "\\begin{instructions}\n";
# remove blank lines from end of array
pop @instructions while $instructions[-1]=~/^\s*$/;
# remove blank lines from the beginning of the array
shift @instructions while $instructions[0]=~/^\s*$/;
print join("\n",@instructions);
# empty instructions array for next pass
@instructions=();
print "\n\\end{instructions}\n\n";
print "$instruct_line\n";

} else {
print "$line\n";
}
}
 
M

Michele Dondi

I have a file named "new".

\backtomargin


In Exercises~\ref{exer2.9.1}--\ref{exer2.9.2}, if the given

Huh?!? Is this clpmisc or ctt?
The spacing is intentional. Now, my perl file is saved as new.pl.

Ah, OK, then you want to (pre-)process a text (specifically, LaTeX)
file...
use strict;
use warnings;
[snip]

I was under the impression that your program was overly complex for
the task it was aimed at. OTOH I was too lazy to try to understand
*exactly* what you meant to do, so from your other post I grabbed the
"working version" and I tried it on your sample. Now, if I'm not
mistaken, the following should serve your needs and is considerably
simpler:

#!/usr/bin/perl -ln

print, next unless /\\backtomargin/;
{
local $/='';
chomp(my $par=<>);
print <<EOT;
\\begin{instructions}
$par
\\end{instructions}

EOT
}

__END__

When I enter:

perl new.pl < new

BTW: no need for '<',

perl new.pl new

will work!


HTH,
Michele
 
T

Trent Curry

thundergnat said:
Andrew said:
On 29 Jun 2004 00:32:36 -0700, (e-mail address removed) (David Arnold)
wrote:
[..]
But there is no space before "\backtomargin" ... so the following
lines never get executed.

I don't know... It looks to me like there is zero or more spaces
before '\backtomargin'.

Correct, ^\s* optionally allows for any whitespace padding before
'\backtomargin'. The person you were quoting, Andrew Lee, was mistaken
:) To that person, I at least recommand O'Reilly's infinately useful
"Perl Pocket Reference, easily avaiable at any good book or computer
store.
Actually, I think the logic problem is the lines:



Since the first line that gets popped off of the array is a blank
line, the while() short circuits and the code block never gets
executed.

Seems to me both of those while's should begin like this: while(defined
$line=...)
if nothing can be pop'ed ot shift'ed off anymroe, undef will be returned
instead, and THEN the loop condition will fail, which sems to be what
was desired, and not if the line was empty, but if something was
returned (aka testing if there is anything left in the array.)

--
Trent Curry - (e-mail address removed)

perl -e
'($s=qq/e29716770256864702379602c6275605/)=~s!([0-9a-f]{2})!pack("h2",$1
)!eg;print(reverse("$s")."\n");'
 
1

187

Michele said:
On 29 Jun 2004 00:32:36 -0700, (e-mail address removed) (David Arnold)
wrote:
I was under the impression that your program was overly complex for
the task it was aimed at. OTOH I was too lazy to try to understand
*exactly* what you meant to do, so from your other post I grabbed the
"working version" and I tried it on your sample. Now, if I'm not
mistaken, the following should serve your needs and is considerably
simpler:

#!/usr/bin/perl -ln

print, next unless /\\backtomargin/;

I dont udnerstand whats going on here. I thought 'next' can only be used
in loops, but here you're tryign to print something? Very confusing,
could you please explain what exactly is happening here?
{
local $/='';
chomp(my $par=<>);
print <<EOT;

And I don't see how you've opened the file. I thought <> read from a
file passed though STDIN, but you say below "no need for '<'" but
withotu that you're just passing "new" to new.pl, and not the file
contends, or am I missing something here..? Thanks for any explainations
you can give, aas I'm quite confused :(
 
S

Sam Holden

I dont udnerstand whats going on here. I thought 'next' can only be used
in loops, but here you're tryign to print something? Very confusing,
could you please explain what exactly is happening here?

perldoc perlrun

And see the description of what the -n command line option that
is being passed to perl (via the -ln in the #! line) does.
And I don't see how you've opened the file. I thought <> read from a
file passed though STDIN, but you say below "no need for '<'" but
withotu that you're just passing "new" to new.pl, and not the file
contends, or am I missing something here..? Thanks for any explainations
you can give, aas I'm quite confused :(

perldoc perlvar

And see the description of ARGV.

<> is equivalent to <ARGV> which manages the opening of files specified
on the command line.
 
1

187

Sam said:
perldoc perlrun

And see the description of what the -n command line option that
is being passed to perl (via the -ln in the #! line) does.

This still deosn't explain why there is a print statement there. Seems
useles there. Can someone please clearly explain this.
 
P

Paul Lalli

This still deosn't explain why there is a print statement there. Seems
useles there. Can someone please clearly explain this.

From the docs:
-n causes Perl to assume the following loop around your
program, which makes it iterate over filename arguments
somewhat like sed -n or awk:

LINE:
while (<>) {
... # your program goes here
}


-l[octnum]
enables automatic line-ending processing. It has two
separate effects. First, it automatically chomps $/
(the input record separator) when used with -n or -p.
Second, it assigns "$\" (the output record separator)
to have the value of octnum so that any print
statements will have that separator added back on. If
octnum is omitted, sets "$\" to the current value of
$/.


So that program is actually:

#/usr/bin/perl

$\ = $/; #because of -l
while (<>) { #because of -n
chomp; #because of -l
print; #explicitly in code
next unless /\\backtomargin/;
}
__END__

The print in the original code is printing the value of $_, which comes
from reading from <>.

Paul Lalli
 
P

Paul Lalli

So that program is actually:

#/usr/bin/perl

$\ = $/; #because of -l
while (<>) { #because of -n
chomp; #because of -l
print; #explicitly in code
next unless /\\backtomargin/;
}
__END__

The print in the original code is printing the value of $_, which comes
from reading from <>.

Paul Lalli

Whoops. That's a rather significant typo. The last two lines of the
while loop should be reversed. Wouldn't be much use otherwise.

#!/usr/bin/perl
$\ = $/; #because of -l
while (<>) { #because of -n
chomp; #because of -l
next unless /\\backtomargin/;
print; #explicitly in code
}
__END__


This actually confuses me. the original code was (effectively):
perl -ln -e 'print, next unless /\\backtomargin/;'

From what I can tell, it looks like the statement containing the print and
next is a comma-separated list being evaluated in void context. In scalar
context, the comma operator evaluates each of its operands from left to
right, discarding the return values of all but the last. Using that
logic, shouldn't the print be evaluated before the next?

Now I've run this myself and verified that it does work as desired. I'm
just confused as to *why* it runs as desired. Does the comma operator do
something different in void context? (quickly checking perldoc perlop --
nope, nothing there).

If someone can clarify for me, I'd appreciate it.

Thanks,
Paul Lalli
 
M

Michele Dondi

I dont udnerstand whats going on here. I thought 'next' can only be used
in loops, but here you're tryign to print something? Very confusing,

In fact we *are* in a loop. But you've already been explained this by
someone else. Here I'll add only that issuing

perl -MO=Deparse new.pl

(assuming the script was called 'new.pl') you will see what's going on
behind the scenes:

BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
print($_), next unless /\\backtomargin/;
{
local $/ = '';
chomp(my $par = <ARGV>);
print
"\\begin{instructions}\n$par\n\\end{instructions}\n\n";
}
}
__DATA__
And I don't see how you've opened the file. I thought <> read from a
file passed though STDIN, but you say below "no need for '<'" but
withotu that you're just passing "new" to new.pl, and not the file
contends, or am I missing something here..? Thanks for any explainations
you can give, aas I'm quite confused :(

Again, you've already been told that. And the answer is in the docs,
as always, but then someone kindly pointed you to the relevant
entries.

Last, I notice only now that the OP's code contained the following
lines

if ($line=~/^\s*\\backtomargin/) {
push (@instructions,$');

suggesting that "\backtomargin" may not come alone on a line, so a
slightly better approximation to what he really wants may be:


#!/usr/bin/perl -lp

next unless s/.*\\backtomargin//;
{
local $/='';
chomp(my $par=<>);
$_ .= <<EOT;
\n\\begin{instructions}
$par
\\end{instructions}

EOT
}

__END__


This is even somewhat simpler than the previous one and... you see?
*Apparently* not even any print() there!!


Michele
 
M

Michele Dondi

This actually confuses me. the original code was (effectively):
perl -ln -e 'print, next unless /\\backtomargin/;'

From what I can tell, it looks like the statement containing the print and
next is a comma-separated list being evaluated in void context. In scalar
context, the comma operator evaluates each of its operands from left to
right, discarding the return values of all but the last. Using that
logic, shouldn't the print be evaluated before the next?

It is, but only if !/\\backtomargin/, i.e. on /\\backtomargin/ it
won't print *and* it won't C<next>.


Michele
 
P

Paul Lalli

Michele Dondi said:
It is, but only if !/\\backtomargin/, i.e. on /\\backtomargin/ it
won't print *and* it won't C<next>.

Okay. I think I understand. So you're saying
perl -lne 'print, next unless /foo/'
is equivalent to
perl -lne 'do {print; next;} unless /foo/'

Is that correct? If so, then I guess my question to the original poster of
that code is what's the point of the 'next' at all? Wouldn't simply '
print unless /foo/ ' do the same thing? (that is, it would do the same
thing in the simple example posted where the line ' print, next unless
/foo/ ' is the only line in a program run with the -ln options). As 'next'
would be the last thing evaluated in the loop block, it would seem to serve
no purpose.

Am I missing something obvious?

Thank you,
Paul lalli
 
M

Michele Dondi

Okay. I think I understand. So you're saying
perl -lne 'print, next unless /foo/'
is equivalent to
perl -lne 'do {print; next;} unless /foo/'

Is that correct? If so, then I guess my question to the original poster of

I would say so.
that code is what's the point of the 'next' at all? Wouldn't simply '
print unless /foo/ ' do the same thing? (that is, it would do the same
thing in the simple example posted where the line ' print, next unless
/foo/ ' is the only line in a program run with the -ln options). As 'next'
would be the last thing evaluated in the loop block, it would seem to serve
no purpose.
Indeed!

Am I missing something obvious?

Well, I can't remember at which point the above cmd line example
popped out. But in the script that I originally posted C<next> was
*not* the last thing evaluated in the loop. So it *did* make sense...


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top