现在的位置: 首页 > 综合 > 正文

wiki文本处理引擎

2013年06月25日 ⁄ 综合 ⁄ 共 6108字 ⁄ 字号 评论关闭
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 tangxiucai2@gmail.com
 * 
 */
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;
		}
	}
}

 

抱歉!评论已关闭.