This is tricky: Which closing brace closes the for
-loop? Either you parse the whole code, or you use some heuristic. In the below solution, I require the intendation of the closing brace to be the same as the intendation of the for
keyword:
$ perl -nE'
if( /^(\s*)for\b/ .. /^$ws\}/ ) {
$ws = $1 // $ws;
/^\s*System\.out\.println/ or print;
} else { print }'
This uses the flip-flop operator COND1 .. COND2
. The script can be used as a simple filter
$ perl -nE'...' <source >processed
or with backup functionality:
$ perl -i.bak -nE'...' source
(creates file source.bak
as backup).
Only tested against the example input; not againts a sensible test suite.
This script passes the GLES Prateek Nina test.
To run this script on all Java files in a directory, do
$ perl -i.bak -nE'...' *.java
Edit
On Windows systems, the delimiter has to be changed to "
. Also, we have to do all globbing ourselves.
> perl -nE"if(/^(\s*)for\b/../^$ws\}/){$ws=$1//$ws;/^\s*System\.out\.println/ or print}else{print}BEGIN{@ARGV=$#ARGV?@ARGV:glob$ARGV[0]}" *.java
Edit 2
Here is an implementation of the brace-counting algorithm I outlined in the comments. This solution does backups as well. The command line arguments will be interpreted as glob expressions.
#!/usr/bin/perl
use strict; use warnings;
clean($_) for map glob($_), @ARGV;
sub clean {
local @ARGV = @_;
local $^I = ".bak";
my $depth = 0;
while (<>) {
$depth ||= /^\s*for\b/ ? "0 but true" : 0;
my $delta = ( ()= /\{/g ) - ( ()= /\}/g );
$depth += $delta if $depth && $delta;
$depth = 0 if $depth < 0;
print unless $depth && /^\s*System\.out\.println/;
}
return !!1;
}
This doesn't do comments either. This will only reckognize System.out.println
-statements that start a new line.
Example usage: > perl thisScript.pl *.java
.
Here is a test file with pseudo-java syntax that I used for testing. All lines marked with XXX
will be gone once the script has run.
/** Java test suite **/
bare block {
System.out.println(...); // 1 -- let stand
}
if (true) {
for (foo in bar) {
System.out.println; // 2 XXX
if (x == y) {
// plz kill this
System.out.println // 3 XXX
} // don't exit here
System.out.println // 4 XXX
}
}
for (...) {
for {
// will this be removed?
System.out.println // 5 XXX
}
}
/* pathological cases */
// intendation
for (...) { System.out.println()/* 6 */}
// intendation 2
for (...)
{
if (x)
{
System.out.println // 7 XXX
}}
// inline weirdness
for (...) {
// "confuse" script here
foo = new baz() {void qux () {...}
};
System.out.println // 8 XXX
}
№ 1 should stay, and does. Statement № 6 should be removed; but these scripts are incapable of doing so.