Depending on how precise you want to be about equality,
you might need to do a fancy floating-point compare:
my $EPSILON = 0.01;
sub approx_equal ( $ $ )
{
my ( $f1, $f2 ) = @_;
return abs( $f1 - $f2 ) < $EPSILON;
}
The most straigntforward filter-style code I could come
up with:
while ( <> )
{
my @in_range = grep { /^[\d.+-]+$/ &&
296.1 <= $_ && $_ <= 314.0 } split /,\s*/;
# skip records with only 305.1 (room temp kelvin?) in range
next if @in_range == 1 && approx_equal( $in_range[0], 305.1 );
print;
}
If this is too slow, it might be faster to bail out
as soon as we know we can:
LINE:
while ( my $line = <> )
{
my $n_305_1 = 0;
my $n_in_range = 0;
foreach my $chunk ( split /,\s*/, $line )
{
# skip non-numeric
next unless $chunk =~ /^[\d.+-]+$/;
# skip values outside the range
next unless 296.1 <= $chunk && $chunk <= 314.0;
# only allowed one value in the given range...
if ( ++ $n_in_range >= 2 )
{
print $line;
next LINE;
}
# and we can only ignore one 305.1
if ( approx_equal( $chunk, 305.1 ) &&
++$n_305_1 > 1 )
{
print $line;
next LINE;
}
}
print $line unless $n_in_range == 1 && $n_305_1 == 1;
if ( $n_in_range == 0)
{
warn "ill-formed line $.: no values in range";
}
}