使用Enjoy的指令实现将html代码压缩为一行:
正则表达式版:
import com.jfinal.template.Directive; import com.jfinal.template.Env; import com.jfinal.template.TemplateException; import com.jfinal.template.expr.ast.ExprList; import com.jfinal.template.io.CharWriter; import com.jfinal.template.io.FastStringWriter; import com.jfinal.template.io.Writer; import com.jfinal.template.stat.Scope; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CompressDirective extends Directive { // 不压缩pre/script/style标签 private static final Pattern ignoredPattern = Pattern.compile("(<pre>(.|\n)*?</pre>)|(<script>(.|\n)*?</script>)|(<style>(.|\n)*?</style>)"); private static final Pattern matchedPattern = Pattern.compile("\\s+"); @Override public void setExprList(ExprList exprList) { if (exprList.length() != 0) { throw new RuntimeException("#compress directive support no parameters only"); } super.setExprList(exprList); } @Override public void exec(Env env, Scope scope, Writer writer) { CharWriter charWriter = new CharWriter(2048); FastStringWriter fsw = new FastStringWriter(); charWriter.init(fsw); stat.exec(env, scope, charWriter); try { StringBuilder temp = fsw.getBuffer(); Matcher ignoredMatcher = ignoredPattern.matcher(temp); int lastIndex = 0; while (ignoredMatcher.find()) { int end = ignoredMatcher.start(); writer.write(compress(temp.substring(lastIndex, end))); writer.write(ignoredMatcher.group()); lastIndex = ignoredMatcher.end() + 1; } // 将最后一个标签后的内容压缩并写入 writer.write(compress(temp.substring(lastIndex, temp.length()))); } catch (IOException e) { throw new TemplateException(e.getMessage(), location, e); } } private String compress(String temp) { Matcher matchedMatcher = matchedPattern.matcher(temp.trim()); // 多个空白字符变为1个 temp = matchedMatcher.replaceAll(" "); return temp; } @Override public boolean hasEnd() { return true; } }
手动分析版:
import com.jfinal.template.Directive; import com.jfinal.template.Env; import com.jfinal.template.TemplateException; import com.jfinal.template.expr.ast.ExprList; import com.jfinal.template.io.CharWriter; import com.jfinal.template.io.FastStringWriter; import com.jfinal.template.io.Writer; import com.jfinal.template.stat.Scope; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class CompressDirective extends Directive { // 不压缩的标签 private static final List<char[]> REQUIRED_TAG_NAMES = buildRequiredTagNames(); private final StringBuilder newString = new StringBuilder(); private int cur = 0; private char[] buf; private char[] currentTagName = null; private static List<char[]> buildRequiredTagNames() { List<char[]> requiredTagName = new ArrayList<>(); requiredTagName.add("pre".toCharArray()); requiredTagName.add("script".toCharArray()); requiredTagName.add("style".toCharArray()); return requiredTagName; } @Override public void setExprList(ExprList exprList) { if (exprList.length() != 0) { throw new RuntimeException("#compress directive support no parameters only"); } super.setExprList(exprList); } @Override public void exec(Env env, Scope scope, Writer writer) { CharWriter charWriter = new CharWriter(2048); FastStringWriter fsw = new FastStringWriter(); charWriter.init(fsw); stat.exec(env, scope, charWriter); buf = fsw.getBuffer().toString().toCharArray(); compress(); try { writer.write(newString.toString()); } catch (IOException e) { throw new TemplateException(e.getMessage(), location, e); } } private void compress() { boolean isLastSpace = false; while (cur < buf.length) { char c = buf[cur]; boolean isSpace = Character.isWhitespace(c); // 多个空白字符只保留一个 if (isLastSpace) { if (!isSpace) { newString.append(c); isLastSpace = false; } } else if (isSpace) { newString.append(' '); isLastSpace = true; } else { newString.append(c); } cur++; if (c == '<') { tryStartTag(); } } } private void tryStartTag() { if (cur == buf.length) { return; } if (!isRequiredStartTag()) { return; } startTagEnd(); while (cur < buf.length) { char c = buf[cur]; newString.append(c); cur++; if (c == '<') { tryEndTag(); if (currentTagName == null) { break; } } } } private void startTagEnd() { while (cur < buf.length) { char c = buf[cur]; newString.append(c); cur++; if (c == '>') { break; } } } private void tryEndTag() { if (cur == buf.length) { return; } if (!isRequiredEndTag()) { return; } startTagEnd(); currentTagName = null; } private boolean isRequiredEndTag() { char c = buf[cur]; if (c != '/') { return false; } cur++; newString.append(c); int length = currentTagName.length; int i = 0; while (i < length) { if (cur == buf.length) { return false; } c = buf[cur]; if (currentTagName[i] != c) { return false; } i++; cur++; newString.append(c); } if (cur == buf.length) { return false; } c = buf[cur]; while (Character.isWhitespace(c)) { newString.append(c); cur++; if (cur == buf.length) { return false; } c = buf[cur]; } return c == '>'; } private boolean isRequiredStartTag() { for (char[] tagName : REQUIRED_TAG_NAMES) { boolean isNeeded = true; int length = tagName.length; int i = 0; while (i < length) { if (cur == buf.length) { isNeeded = false; break; } char c = buf[cur]; if (c != tagName[i]) { isNeeded = false; break; } newString.append(c); cur++; i++; } if (isNeeded && cur < buf.length) { if (Character.isWhitespace(buf[cur]) || buf[cur] == '>') { currentTagName = tagName; return true; } } } return false; } @Override public boolean hasEnd() { return true; } }
在配置中添加该指令:
engine.addDirective("compress", CompressDirective.class);
即可使用指令:
#compress() <!doctype html> <html> <head> <meta charset="UTF-8"> <title>压缩测试</title> <style> body { margin: 0; } </style> </head> <body> 压 缩 <pre> 原样输出 </pre> <script> //原样输出 </script> </body> </html> #end