To my astonishment I found out that there are very few free javascript compressors out there, and most of them don’t actually work. I came across Mike Hall’s Javascript Crunchinator, a javascript compressor which, being written in Javascript, is very slow and didn’t work for my sample complex script. The other worth mentioning compressor was a Perl snippet written by Mihai Bazon. I decided I wanted one written in Java instead, so I sat down and cranked out the following just so that you have yet one more option…
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The compactor can be used to compact java scripts by removing comments,
* leading and trailing whitespaces, newlines, and condense any spaces between
* operators, parentheses, brackets etc. It only works if all statements
* (including classes and simple functions) are properly
* terminated by semicolons. If you read the script from a file using
* readLine() method make sure you put the new line character back at the end
* of the line, as readLine() consumes it.
*/
public class JavascriptCompactor {
public static String compactJSCode(String sCode) {
// Protect single and double quoted strings.
Pattern strings = Pattern.compile("\"(\\\\.|[^\"\\\\])*\"
|'(\\\\.|[^'\\\\])*'");
Matcher m = strings.matcher(sCode);
StringBuffer sb = new StringBuffer();
HashMap theStrings = new HashMap();
while (m.find()) {
String sReplacement = "__STR_" + theStrings.size();
theStrings.put(sReplacement, m.group());
m.appendReplacement(sb, sReplacement);
}
m.appendTail(sb);
sCode = sb.toString();
// remove C style comments
Pattern pattern = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
sCode = pattern.matcher(sCode).replaceAll("");
// remove C++ style comments.
sCode = sCode.replaceAll("//.*?\\n", "");
// remove leading/trailing whitespaces.
sCode = sCode.replaceAll("(?:(?:^|\\n)\\s+|\\s+(?:$|\n))", "");
// remove newlines.
sCode = sCode.replaceAll("\\r?\\n", "");
// remove spaces around operators etc.
sCode = sCode.replaceAll("\\s+", " ");
sCode = sCode.replaceAll("\\s([\\x21\\x25\\x26\\x28\\x29 \
\\x2a\\x2b\\x2c\\x2d\\x2f\\x3a\\x3b\\x3c\\x3d\\x3e\\x3f
\\x5b\\x5d\\x5c\\x7b\\x7c\\x7d\\x7e])", "$1");
sCode = sCode.replaceAll("([\\x21\\x25\\x26\\x28\\x29
\\x2a\\x2b\\x2c\\x2d\\x2f\\x3a\\x3b\\x3c\\x3d\\x3e\\x3f
\\x5b\\x5d\\x5c\\x7b\\x7c\\x7d\\x7e])\\s", "$1");
// Put back strings.
m = Pattern.compile("__STR_\\d+").matcher(sCode);
StringBuffer result = new StringBuffer();
int iLastEnd = 0;
while (m.find()) {
result.append(sCode.substring(iLastEnd, m.start()));
result.append((String) theStrings.get(m.group()));
iLastEnd = m.end();
}
result.append(sCode.substring(iLastEnd));
return result.toString();
}
}