使用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