On Thu, Apr 12, 2007 at 08:59:39PM +0200, Marek Stepanek wrote:
> On 12.04.2007 18:16, "Ronald J Kimball" <[EMAIL PROTECTED]> wrote:
>
> > If you set $/ to undef, then you're asking Perl to read in the entire input
> > all at once. Therefore, your loop only executes once, your m//g only
> > matches once, and your s///g replaces every entry with the results
> > from that one match.
>
> this I don't understand! m//g should find ALL matches, also in a file read
> in at once, because of the g (=global) modifier ???
m//g in a scalar context will find all matches, but only one a time. Each
time the m//g is executed, it finds the next match. If you only execute
the m//g once, as in your script, then the /g doesn't have any effect.
(In a list context, m//g means find all the matches right now.)
This is different from s///g, which always finds and replaces all the
matches, regardless of context.
> 1 while
> s{/[.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([&\d]+)\t&\t([&\d]+)\t&
> \t&\t&\t&\t[A-Z]+\t\\\\\n[.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([
> &\d]+)\t&\t([&\d]+)\t.+/i}{
> my ($km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2, $km2_2,
> $stiche_2, $zschl_2, $sum_2) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
> tr/&/./ for ($km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2,
> $km2_2, $stiche_2, $zschl_2, $sum_2);
> $km1_dif = sprintf ("%.2f",$km1_2 - $km1_1);
> $km2_dif = sprintf ("%.2f",$km2_2 - $km2_1);
> $stiche_dif = $stiche_2 - $stiche_1;
> $zschl_dif = sprintf ("%.2f",$zschl_2 - $zschl_1);
> $sum_dif = sprintf ("%.2f",$sum_2 - $sum_1);
> tr/./&/ for ($km1_dif, $km2_dif, $stiche_dif, $zschl_dif, $sum_dif);
>
> s/TOTAL\t.+/TOTAL\t&\t$km1_dif\t&\t$km2_dif\t&\t$stiche_dif\t&\t$zschl_dif\t
> &\t$sum_dif\t/}gie;
>
> print OUT;
Sorry, I think my example was a little unclear. m// and s/// can take
alternate delimiters, like m;; or s!!!. They can also take balanced
delimiters, like m<> or s{}{}. Instead of s{/regex/i}{replace}gie, you
just want s{regex}{replace}gie;
s///e means execute the replacement as Perl code, and use the result as the
replacement string. s/(\d+)\+(\d+)/$1 + $2/e; would replace 2+2 with 4.
My example also wasn't completely correct. I see now that the first regex
doesn't match the TOTAL line. As that's part of what is being replaced by
the s{}{}, it should be included in the match.
And, um, I just realized, s///g is already going to find all the matches,
so the 1 while is not needed (and could actually result in an infinite
loop! oops!).
So, with all those clarifications and corrections, the script would look
something like this:
#!perl
undef $/;
$_ = <>;
s{([.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([&\d]+)\t&\t([&\d]+)\t&\t&\t&\t&\t[A-Z]+\t\\\\\n[.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([&\d]+)\t&\t([&\d]+)\t.+\n)TOTAL\t.+}
{
my($entries, $km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2, $km2_2,
$stiche_2, $zschl_2, $sum_2) =
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);
tr/&/./ for ($km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2,
$km2_2, $stiche_2, $zschl_2, $sum_2);
$km1_dif = sprintf ("%.2f",$km1_2 - $km1_1);
$km2_dif = sprintf ("%.2f",$km2_2 - $km2_1);
$stiche_dif = $stiche_2 - $stiche_1;
$zschl_dif = sprintf ("%.2f",$zschl_2 - $zschl_1);
$sum_dif = sprintf ("%.2f",$sum_2 - $sum_1);
tr/./&/ for ($km1_dif, $km2_dif, $stiche_dif, $zschl_dif, $sum_dif);
$entries .
"TOTAL\t&\t$km1_dif\t&\t$km2_dif\t&\t$stiche_dif\t&\t$zschl_dif\t&\t$sum_dif\t";
}gie;
print;
__END__
Note that I added an extra pair of capturing parentheses, to grab and
preserve the first two lines in the entry, and that instead of using
another substitution, I just create a whole new TOTAL line.
> I tried your second suggestion, but it is not working either! Suppose
> because in my <IN> file, the lines are not regular ... So if I read in two
> lines by two lines, it will sometimes match the double line, we are looking
> for, but sometimes not, depending the empty lines between ... (I will paste
> the entire <IN> file at the end) ...
Yes, if there are blank lines, or entries split across multiple lines, or
even header lines that should be ignored, those will throw things off, for
the way I did my example.
How do you recognize a complete entry?
Based on the sample file, it looks like the entries are separated by blank
lines, so you could do this:
#!perl
$/ = '';
while (<>) {
if
(m/[.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([&\d]+)\t&\t([&\d]+)\t&\t&\t&\t&\t[A-Z]+\t\\\\\n[.\d]+\t&\t([&\d]+)\t&\t([&\d]+)\t&\t([\d]+)\t&\t([&\d]+)\t&\t([&\d]+)\t.+/i)
{
my($km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2, $km2_2,
$stiche_2, $zschl_2, $sum_2) =
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
tr/&/./ for ($km1_1, $km2_1, $stiche_1, $zschl_1, $sum_1, $km1_2,
$km2_2, $stiche_2, $zschl_2, $sum_2);
$km1_dif = sprintf ("%.2f",$km1_2 - $km1_1);
$km2_dif = sprintf ("%.2f",$km2_2 - $km2_1);
$stiche_dif = $stiche_2 - $stiche_1;
$zschl_dif = sprintf ("%.2f",$zschl_2 - $zschl_1);
$sum_dif = sprintf ("%.2f",$sum_2 - $sum_1);
tr/./&/ for ($km1_dif, $km2_dif, $stiche_dif, $zschl_dif, $sum_dif);
s/TOTAL\t.+/TOTAL\t&\t$km1_dif\t&\t$km2_dif\t&\t$stiche_dif\t&\t$zschl_dif\t&\t$sum_dif\t/;
}
print;
}
I tested both scripts, and they seem to work. :)
Ronald
--
------------------------------------------------------------------------
Have a feature request? Not sure the software's working correctly?
If so, please send mail to <[EMAIL PROTECTED]>, not to the list.
List FAQ: <http://www.barebones.com/support/lists/bbedit_script.shtml>
List archives: <http://www.listsearch.com/bbeditscripting.lasso>
To unsubscribe, send mail to: <[EMAIL PROTECTED]>