package me.txc.idiom; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Wiki文字处理引擎 * <p> * 常用wiki体列举如下: * <ol> * <li>直接闭合 * <ul> * <li> ---- 对应 </hl> </li> * <li> > 对应 <ul> </li> * <li> >> 对应 <li> </li> * </ul> * </li> * <li>单值 * <ul> * <li> [img[xxx.jpg]] 对应 </hr> </li> * <li> ``xxx`` 对应 <b> xxx </b></li> * <li> //xxx// 对应 <i> xxx </i></li> * </ul> * </li> * <li>多值 * <ul> * <li> @@color(red):xxx@@ 对应 <font color="red"> xxx </font> * </li> * <li> @@bgcolor(red):xxx@@ 对应 <span background="red"> xxx * </span> </li> * </ul> * </li> * <li>特殊处理 * <ul> * <li>表格</li> * <li>列表</li> * </ul> * </li> * </ol> * </p> * * @author [email protected] * */ public class WikiTextEngine { private final static int NONE_VALUE = 0; private final static int SINGLE_VALUE = 1; public static void main(String[] args) { WikiTextEngine wh = new WikiTextEngine(); wh.addWikiText("``", "<b>$1</b>", "文字加粗", "", 1); wh.addWikiText("//", "<i>$1</i>", "文字倾斜", "", 1); wh.addWikiText("----", "<hr>", "横线", "", 0); wh.addWikiText("@@color()", "<font color=\"$1\"/>$2</font>", "文字颜色", "@@color\\((.+?)\\):(.+?)@@", 2); wh.addWikiText("@@bgcolor()", "<span background=\"$1\">$2</span>", "文本背景色", "@@bgcolor\\((.+?)\\):(.+?)@@", 2); wh.addWikiText("--", "删除", new WikiTextHandler(){ @Override public String process(String target) { String regex = "--(.+?)--"; if(Pattern.matches(regex, target)){ Pattern pattern = Pattern.compile(regex); for(Matcher matcher = pattern.matcher(target); matcher.find();){ String findStr = matcher.group(); String includedStr = matcher.group(1); String newStr = "(已删除:" +includedStr+ ")"; target = target.replaceAll(findStr, newStr); } } return target; }}); String[] demo = new String[] { "abc----", "``hello``", "//he llo//", "@@color(blue):This is --some-- text.@@", "@@bgcolor(red):文本 背景.@@", "--xxx--yyy--zzz--" }; for (String str : demo) System.out.println(wh.process(str)); } /** * 添加Wiki体 * * @param symbol * 符号 起到键的作用,需要保持唯一 * @param text * 替代的HTML文本,$1代表发现的剔除符号外的文本的占位符 例如 要将``xxx``最终替换为 * <b>xxx</b>则这里的text设为<b>$1</b>,要将[img[xxx.jpg]]最终替换为<img * src="xxx.jpg"/>则这里的text需设为<img src="$1"/> * @param meaning * 符号表示的含义 * @param regex * 符号匹配的正则,如果存在对应的正则,则按照设定的正则进行特殊匹配 例如 [img[(\\w+)]] 可以匹配 * [img[xxx.jpg]];否则将默认按照首尾一致的原则进行匹配 例如 --(\\w+)-- * 但是所有组装出的正则中不应该在存在() * @param valueCount * 占位符个数:取值0/1/2/... 不可设为-1(-1表示自定义解析规则) 即例如 * <hr/>为0个,<b>xx <b>为1,< font * color="$1">$2 </font> */ public void addWikiText(String symbol, String text, String meaning, String regex, int valueCount) { WikiTextManager.getContainer().add( this.new WikiText(symbol, text, meaning, regex, valueCount)); } /** * 添加Wiki体 * * @param symbol * 符号 * @param meaning * 含义 * * @param handler * 自定义处理规则 * * @see #addWikiText(String, String, String, String, int) */ public void addWikiText(String symbol, String meaning, WikiTextHandler handler) { WikiTextManager.getContainer().add( this.new WikiText(symbol, meaning, handler)); } /** * 移除指定的Wiki体 * * @param symbol * 符号 */ public void removeWikiText(String symbol) { WikiTextManager.getContainer().remove(symbol); } /** * 处理wiki体转义为HTML * * @param target * 需要处理的目标字符串 * @return 处理后的字符串 */ public String process(String target) { if (target == null || "".equals(target)) return ""; String result = target; for (Iterator<WikiText> it = WikiTextManager.getContainer().iterator(); it .hasNext();) { result = replace(it.next(), result); } return result; } /** * 匹配处理规则:如果存在对应的正则,则按照设定的正则进行特殊匹配 例如 [img[(\\w+)]] 可以匹配 * [img[xxx.jpg]];否则将默认按照首尾一致的原则进行匹配 例如 --(\\w+)-- 可以匹配 * --xxx--,但是所有组装出的正则中不应该在存在() * * @param wt * @param target */ private String replace(WikiText wt, String target) { if (wt.valueCount == -1) { if (wt.handler == null) // 如果没有对应的处理规则实现则不做处理 return target; else return wt.handler.process(target); } String regex = currentRegex(wt); Pattern pattern = Pattern.compile(regex); for (Matcher matcher = pattern.matcher(target); matcher.find();) { // 获取当前完全匹配的组 String orginalText = matcher.group(); String newText = ""; if (wt.valueCount == NONE_VALUE) { newText = wt.text; } else if (wt.valueCount == SINGLE_VALUE) { // 目标文本 如 [img[xxx.jpg]]通过这步后获取到xxx.jpg String targetText = matcher.group(1); // 拼接新的html的串 即 <img src="$1"> 还原为 <img src="xxx.jpg"> newText = wt.text.replace("$1", targetText); } else { // 处理多值问题例如 <font color="$1" attr="$n">$2</font> for (int i = 1; i <= matcher.groupCount(); i++) { String targetText = matcher.group(i); String tmpReg = "{1}quot; + i; wt.text = newText = wt.text.replace(tmpReg, targetText); } } target = target.replace(orginalText, newText); } return target; } private String currentRegex(WikiText wt) { String regex = null; // 多值情况下需要自定义正则,并且要使用占位符 if (wt.regex != null && !"".equals(wt.regex)) regex = wt.regex; // 无值时正则本身就是符号 else if (wt.valueCount == 0) regex = wt.symbol; // 默认当做单值,则正则为前后一致 else regex = wt.symbol + "(.+?)" + wt.symbol; return regex; } // -------------------------------------------------------------- /** * Wiki体管理器 * * @author tangxiucai * */ private static class WikiTextManager { private static Set<WikiText> container = new HashSet<WikiText>(); public static synchronized Set<WikiText> getContainer() { return container; } } /** * Wiki特殊符号自定义解析接口 * 自定义解析规则需要注意参数为整个需要处理的字符串,有可能被应用了其他规则也可能没有,这取决于规则的应用顺序。 * 通常自定义规则接口实现步骤:①进行匹配操作,只有在匹配成功的情况下对目标串进行处理否则返回原目标串, * 而不能返回null或空串因为可能导致空指针异常; ②对匹配串进行迭代处理 * 实现示例: * <code><pre> * public String process(String target) { String regex = "--(.+?)--"; if(Pattern.matches(regex, target)){ Pattern pattern = Pattern.compile(regex); for(Matcher matcher = pattern.matcher(target); matcher.find();){ String findStr = matcher.group(); String includedStr = matcher.group(1); String newStr = "(已删除:" +includedStr+ ")"; target = target.replaceAll(findStr, newStr); } } return target; } *</pre></code> * @author tangxiucai * */ private interface WikiTextHandler { /** * 自定义处理过程,将目标字符串按照自己的解析规则转换成需要的字符串 * * @param target * 需要处理的目标字符串 * @return 处理后的字符串 */ String process(String target); } /** * Wiki体 * * @author tangxiucai * */ private class WikiText { /** * 符号 例如 --表示删除 ----表示横线 */ public String symbol; /** * 对应的html,用$1代表目标串的占位符 */ public String text; /** * 符号含义 */ public String meaning; /** * 符号匹配正则 */ public String regex; /** * 存储占位符个数 -1时说明存在自定义解析接口的实现 */ public int valueCount; public WikiTextHandler handler = null; public WikiText(String symbol, String text, String meaning, String regex, int valueCount) { this.symbol = symbol; this.text = text; this.meaning = meaning; this.regex = regex; this.valueCount = valueCount; } public WikiText(String symbol, String meaning, WikiTextHandler handler) { this.symbol = symbol; this.meaning = meaning; this.handler = handler; this.valueCount = -1; } @Override public int hashCode() { return this.symbol.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof WikiText)) return false; WikiText wt = (WikiText) obj; if (wt.symbol.equals(this.symbol)) return true; return false; } } }