Most Recent Blog

King's View of the Battle

 Open GL model of a chess board.

August 29, 2012

Unique Static Content and Eclipse Non-Consume Regex Glitch

I discovered a technique to allow infinite cache expire time for images and static content on websites. This technique is highly desirable because image requests and 304 requests consume time and make the user experience poor.  The technique is to include a version as follows:
 



-
 

In Fact, in the above example you could be even more sophisticated and include the MD5-checksum or other very unique identifier.
So I cracked open Eclipse to make the REGEX search and replace.  The expression I came up with was:
#Search RegEx
# This looks for .jpg, and then does a 
# NON-Consuming match on a word boundary where there is NOT a ?
# For example .jpg" and .jpg' would match, but .jpg?version2 will not
\.jpg(?\b)(?[^\?])
#Replacement
\.jpg?STATIC_CONTENT_VERSION

I proceeded to do the simple search and replace.

To my chagrin, I received the infamous Error:
, "Match string has changed in the file" 


Why is this?  Well I googled it.  It is a know bug with Eclipse and regexes...
Eclipse Bug.

Workaround:  well we could use Netbeans, but I choose to go more primitive and use perl.  This post will include the generic perl script developed to solve the simple issue and how it was used:

To use, simple type perl findreplace.pl regexSearch regexReplace [0|1]
The 0 is a dryrun, the 1 will really do the replace.

use File::Find;
use File::Basename;

# The inputs:
# directory to start in, findRegex, replacement, dryrun indicator
@DIRS = $ARGV[0];
$patternFind = $ARGV[1];
$patternReplace = $ARGV[2];
$dryrun = $ARGV[3];

#  process a single file (this sub is called from below)
sub processFile{

    $baseN="";
    $dirN="";
    $extN="";
    $linesProcessed = 0;
    $currentFile = $File::Find::name;
    ($baseN,$dirN,$extN) = fileparse($currentFile,'\..*');
    if ($extN eq ".java" || 
        $extN eq ".jsp"  ||
        $extN eq ".properties" ||
        $extN eq ".js" ||
        $extN eq ".css" ){
        # This represents a file that we want to do a search and replace on.
        # print "found java $currentFile :$extN:$baseN:$dirN:\n";
    }else{
        # print "\nRETURNING: $currentFile\n\n";
        return;
    }

    $currentBaseName = $_;

    # OPEN THE FILE READ ONLY.
    open FILE, $currentBaseName;
    $modify= 0;
    # DETERMINE IF THE FILE CONTAINS A MATCH
    while($line =){
        if($line =~ /$patternFind/){
            $modify++
        }
    }
    close FILE;
    if($modify==0){
        # THERE WAS NO REGEX MATCH, SO EXIT.
        return;
    }

    # NO IT's not the evil number, 
    # it means set to global read/write in unix.
    # required for TFS integration.
    chmod 0666, $currentBaseName;

    open (FILE, "+< $currentBaseName")  or die "can't read $currentFile $!";
    $out = '';
    while(){
        if($_ =~ /$patternFind/){
            $linesProcessed++;
        print "\tReplace: $_\n";
            s/$patternFind/$patternReplace/eg;
        print "\tWith: $_\n";
        }

        $out .=$_;
    }

    if($dryrun==1){

        seek(FILE,0,0) or die "can't seek to start of $currentFile $!";
        print FILE $out or die "cant't print $currentFile $!";
        truncate(FILE, tell(FILE))  or die "can't truncate $currentFile: $!";
        close (FILE)         or die "can't close $currentFile: $!";

    }

    print "File:$baseN$extN :From ->:$dirN\n";
    print "Lines Changed: $linesProcessed\n";
    print "___________________________________________________\n";
}
find (\&processFile, @DIRS);

hope you find this useful!