package com.jeecms.core.util;
import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map;
import com.jeecms.article.entity.Article;
/** * @author fisher 2009-9-1 上午10:39:09 * * 类说明:包含HTML标签的文本分页处理 */ public class HtmlPage { /** * 方法说明:测试类 * * @param args * * @author fisher */ @SuppressWarnings("unchecked") public static void main(String[] args) { HtmlPage testHtmlPage = new HtmlPage(); String text = " "+ "\nhttp://www.botwave.com/ctwap/res_base/gznet_com_wap/upload/article/image/2009_3/9_2/cut_fcff6W020090902600288145093.jpg\" alt=\"\" /> "+ "\n 中山大道珠吉路口西面一处施工路段,路面车辆为避开前方工地,不得不纷纷越双黄线变道 "+ "\n 市民投诉标线不清、新旧标线难辨、“被迫违法越线”等 "+ "\n 交警表示临时标线 由施工单位负责 近期将讨论统一问题 "+ "\n 本报讯 (记者卢迎新摄影报道)李生上周驾自家货车行驶在中山大道东圃客运站附近时,在变道时与相邻直行车道一辆奔驰轿车发生碰撞,交警判定由于李生的货车在变更车道时未留出安全距离避让原车道直行的奔驰车导致事故,李生负全责。李生则认为,虽然自己要负责任,但是前方的BRT工地将好好的直行车道“拦腰截断”了,是否也要负责任。 "+ "\n 记者在采访中发现,不少经常途经中山大道一带的驾车一族市民对施工工地附近的临时标线的确多有怨言,标线不清、新旧标线难辨、“被迫违法越线”等成为问题的集中点,更有市民担忧,不法“撞车党”会否利用这个空隙,专门守在这些标线存在问题的路段进行撞车敲诈? "+ "\n 直行车道变“断头路” "+ "\n 昨日下午,记者在中山大道科韵路的一处施工工地前看到,3条直行车道在工地前“中断”,成了“断头车道”,原本沿着东往西方向行驶的直行车辆为了避开用塑料水马围蔽起来的工地,不得不冒着违规压实线的危险变道。 "+ "\n “这个‘断头路’也来得太突然了吧,司机要是反应慢一点就要违规压实线了,”私家车主陆小姐抱怨说,“此外,能否在工地前方与直行车道的交会处画一个导流带呢?” "+ "\n 为避工地司机变线 "+ "\n 记者昨日下午多次驱车实地观察了中山大道BRT沿线,从岗顶-棠下-棠东-车陂-东圃一路行去,发现施工工地周边标线不清的情况并非独此一处。在中山大道珠吉路口西面一处施工路段,路面车辆为避开前方工地,不得不纷纷越双黄线变道。 "+ "\n 此外,在中山大道天河公园对出路段东往西方向,也存在围蔽工地前车辆“被迫违法越线”的问题。而位于原来的旧交通灯附近、实线密布的围蔽工地,路过工地的路面车辆更是不得不“被迫违法越线”。 "+ "\n 在中山大道华景新城华润万家对出路段、武警广东总队等地段则多处存在新旧标线不易辨识的问题。“太阳光一反射,哪里是新线哪里是旧线就更难分清了”。有市民抱怨说。 "+ "\n 交警:已注意到标线混乱 "+ "\n 天河交警方面相关人士昨日透露,BRT施工期间,施工路面的临时标线是由各个施工单位组织标画和落实的,交警方面亦已注意到标线混乱的问题,近期计划召集各个施工单位开会讨论标线的统一问题。交警方面同时坦言,BRT施工的业主方就有两三个,下面的分包商更是难以统计,“管理有难度”。 "+ "\n 一位包工头则告诉记者:“一些标线及时更新了,有些也没有及时更新,是因为更新标线需要时间和金钱,很难保证各个承包方都那么负责的。” "+ "\n 交警建议,行驶在工地林立的中山大道沿线的司机,变换车道时应注意避让直行车辆,以免造成不必要的损失。 "+ "\n 记者踩点 "+ "\n [体育中心南门]路过车屡踩线 "+ "\n 相对于其他节点,BR T工程体育中心段开工还算晚的,但即便如此,该节点也未改变标线混乱“老毛病”。昨日下午,记者从购书中心往东行走,在地下隧道入口处,一条明显的白色实线“横”在路口,许多车辆经过时都会“踩线”。 "+ "\n [岗顶]不压实线就撞墙 "+ "\n 在中山大道隆德大厦对出马路,由于原5条车道只剩两条,过往车辆遭遇瓶颈。记者在现场看到,该路段中间已围蔽,车道被水马墙拦住,车辆若直行必然撞墙。 "+ "\n [天河软件园]老实司机被迫“违章” "+ "\n 昨日上午,市民符先生开车到中山大道天河软件园门前,眼前一条白色实线分开了BR T工地与剩余车道,若想通过该路口,他的唯一选择就是“违章”变线。 "+ "\n [天河公园北门]不知该走哪条路 "+ "\n 在天河公园北门,穿梭行人、车辆异常集中。而就在公园北门往西一点,就是更为混乱的交通标线。“有的标线竟指两条道,不知道该走哪条道!”市民王伯抱怨说。 "+ "\n [车陂路口]连交通标线也没有 "+ "\n “要么划线好混乱,要么干脆不划线!”家住天河天朗明居的李女士,如此形容进出小区的遭遇。在车陂路口段,因BR T施工,马路中间被圈起来,天河红十字会门前,连基本的交通标线都没有。 "+ "\n [东圃]双黄标线也得“踩” "+ "\n 双黄实线是不能横跨的。可就在天河莲溪北侧公交站前,受BR T莲溪节点影响,该路原有分割线被取消,原由西往东两条车道,被临时用作由东往西一侧,原有北侧向西行驶车道被封闭,许多司机不敢贸然“踩”双黄实线。 "+ "\n ■交警说法 "+ "\n BRT沿线车辆变线处罚放宽 "+ "\n 问(记者):因变线而撞车的陈先生,坚持认为自己被迫变线,对此该怎样看待? "+ "\n 答(天河交警有关负责人):按有关规定,若因变线而撞上直行车辆,变线司机负全责,这与标线问题无必然关系。 "+ "\n 问:BRT沿线标线问题诸多,你们会如何改进? "+ "\n 答:目前BRT路面标线确实很混乱,施工单位常变动围蔽点,我们将与各施工方沟通,及时改善道路标线。 "+ "\n 问:标线有不足,那车辆变线是否违规? "+ "\n 答:我们已对BRT沿线车辆变线处罚有所放宽,若确须变线则不受处罚。但这并不意味可随意变线。 "+ "\n 问:司机不知道如何应对标线迷宫,如何避免发生事故? "+ "\n 答:若原有线路直行受阻,车主可合理变线,但先要观察后面车辆,让路直行车辆。 "; // text = "直行车道变“断头路阿萨嘎事故奥斯 丁 士大夫A 路”"; String pageCompleText[] = testHtmlPage.getComplePageText(text, 100); System.out.println("#####-----------------------------------------------"); System.out.println(pageCompleText.length); for(int i = 0; i < pageCompleText.length; ++i) System.out.print(pageCompleText[i]); System.err.println("---------------------------------------------------"); text = text.replaceAll(Article.SPLIT_REG, ""); text = text.replaceAll(Article.TRS_SPLIT_REG, ""); if(text.length() <= 100) return; HtmlPage hp = new HtmlPage(); String pageText[] = hp.getComplePageText(text, 100); if(pageText == null) { return; } StringBuffer pageContent = new StringBuffer(); for(int i = 0; i < pageText.length; ++i) { pageContent.append(pageText[i]); pageContent.append(Article.SPLIT); } System.err.println(pageContent); } /** * 方法说明:对含Html标签的文本进行分页 * 步骤:1. 计算虚拟字符下标Map * 2. 获取标签列表 * 3. 分页 * 4. 补齐标签 * * @param text * 包含Html标签的文本 * @param pageSize * 页长 * @return * 返回分页好的字符数组 * @author fisher */ @SuppressWarnings("unchecked") public String[] getComplePageText(String text, int pageSize) { if(text == null || "".equals(text) || pageSize < 1 ||text.length() <= pageSize) return null; text = text.replace(" ", ""); char[] textCharArr = text.toCharArray(); if(isLeftBracket(textCharArr[0])) { text = "." + text; } if(isRightBracket(textCharArr[textCharArr.length - 1])) { text = text + "."; } Map indexMap = getVirtualIndex(text); List list = getBracketList(text); return page(text, indexMap, list, pageSize); } /** * 方法说明:补齐标签 * * @param pageText * 分页好的文本 * @param indexMap * 虚拟字符下标记录Map * @param list * 标签列表 * @param textLengt * 文本长度 * @param pageSize * 页字符数 * @return * * @author fisher */ // @SuppressWarnings("unchecked") // // TODO:效率较低,可以考虑其他方案 // public String[] complementarityContent(String[] pageText, Map indexMap, List list, int textLengt, int pageSize) { // // if(pageText.length < 1 || pageSize < 1) // return null; // Tag tag; // String page, tempPage; // String[] compPageText = new String[pageText.length]; // Integer pageBeginIndex, pageEndIndex, endIndex; // for(int i = 0; i < pageText.length; ++i) { // page = pageText[i]; //// pageBeginIndex = (Integer) indexMap.get(i * pageSize); //// pageBeginIndex = pageBeginIndex == null?0:pageBeginIndex; //// // 去掉所有<>元素, //// tempPage = filterBracket(page); //// pageEndIndex = (Integer) indexMap.get(i * pageSize + tempPage.length() - 1) ; //// pageEndIndex = pageEndIndex == null?textLengt-1:pageEndIndex; // // endIndex = (i+1) * pageSize -1; // pageEndIndex = (Integer)indexMap.get(endIndex); // pageEndIndex = pageEndIndex == null?textLengt-1:pageEndIndex; // pageBeginIndex = pageEndIndex == 0?0:pageEndIndex + 1; // // if(!list.isEmpty()) // for(Iterator it = list.iterator(); it.hasNext();) { // tag = (Tag) it.next(); // // 假设page: "abcd" ; tag: // /* // * 可能的情况 // * 1. pageContent1 abcd pageContent2 pageContent3 // * 2. pageContent1 pageContent2 abcd pageContent4 // * 3. pageContent1 pageContent2 abcd // * 4. pageContent1 abcd // * 5. pageContent1 abcd pageContent2 // * 6. abcd // * 7. abcd pageContent // * 8. abcd pageContent .. 14 // */ // if(tag.getStartIndex() + tag.getStartTag().length() == pageBeginIndex&& tag.getEndIndex() > pageEndIndex) { // // 原来的情况:pageContent1 abcd pageContent2 pageContent3 // // 分页之后的情况:abcd // // 补齐标签:abcd // page = page + tag.getEndTag(); // } else if(tag.getEndIndex() == pageEndIndex && tag.getStartIndex() < pageBeginIndex) { // // 原来的情况:pageContent1 pageContent2 abcd pageContent4 // // 分页之后的情况:abcd // // 补齐标签:abcd // page = tag.getStartTag() + page; // } else { // if(tag.getStartIndex() < pageBeginIndex && tag.getEndIndex() < pageBeginIndex) { // // 原来的情况: pageContent1 pageContent2 abcd // // 分页之后的情况:abcd // // 补齐标签:不需要 // // page = page; // } else if(tag.getStartIndex() < pageBeginIndex && // tag.getEndIndex() > pageBeginIndex && tag.getEndIndex() < pageEndIndex) { // // 原来的情况: pageContent1 abcd // // 分页之后的情况:abcd // // 补齐标签:abcd // page = tag.getStartTag() + page; // } else if(tag.getStartIndex() < pageBeginIndex && tag.getEndIndex() > pageEndIndex) { // // 原来的情况: pageContent1 abcd pageContent2 // // 分页之后的情况:abcd // // 补齐标签:abcd // page = tag.getStartTag() + page + tag.getEndTag(); // } else if(tag.getStartIndex() > pageBeginIndex && tag.getEndIndex() < pageEndIndex) { // // 原来的情况:abcd // // 分页之后的情况:abcd // // 补齐标签:不需要 // // page = page; // } else if(tag.getStartIndex() > pageBeginIndex && tag.getStartIndex() < pageEndIndex // && tag.getEndIndex() > pageEndIndex) { // // 原来的情况:abcd pageContent // // 分页之后的情况:abcd // // 补齐标签:abcd // page = page + tag.getEndTag(); // } else if(tag.getStartIndex() > pageEndIndex) { // // 原来的情况:abcd pageContent .. // // 分页之后的情况:abcd // // 补齐标签:不需要 // // page = page; // } else { // // 不需要补齐 // // page = page; // } // } // } // compPageText[i] = page; // } // return compPageText; // } /** * 方法说明:根据虚拟字符下标记录Map和pageSize进行分页 * * @param text * 初始文本 * @param indexMap * 虚拟字符下标记录Map * @param pageSize * 页字符数 * @return * 返回分页好的字符数组 * @author fisher */ public String[] page(String text, Map indexMap, List list, int pageSize) { String[] pageText, compPageText; String tempText = filterBracket(text); // 去除<>标签的文本长度 int tempLen = tempText.length(); int length = text.length(); if(tempLen <= pageSize) { pageText = new String[1]; pageText[0] = text; return pageText; } int mapSize = indexMap.size(); int realSize = mapSize / pageSize; if(realSize <= 1) { pageText = new String[1]; pageText[0] = text; return pageText; } pageText = new String[realSize + 1]; compPageText = new String[realSize + 1]; Integer endIndex = 0; Integer pageBeginIndex = 0; Integer pageEndIndex = 0; Tag tag; String page; for(int i = 0; i <= realSize; ++i) { pageBeginIndex = pageEndIndex == 0?0:pageEndIndex + 1; endIndex = (i+1) * pageSize -1 ; pageEndIndex = (Integer)indexMap.get(endIndex); pageEndIndex = pageEndIndex == null?length-1:pageEndIndex; while(text.substring(pageEndIndex + 1).startsWith("")) { // 下一个是 pageEndIndex = this.getNextRightBracket(text, pageEndIndex + 1); } pageEndIndex = pageEndIndex == null?length-1:pageEndIndex; pageText[i] = text.substring(pageBeginIndex, pageEndIndex + 1); // 补齐标签 page = pageText[i]; if(!list.isEmpty()) for(Iterator it = list.iterator(); it.hasNext();) { tag = (Tag) it.next(); // 假设page: "abcd" ; tag: /* * 可能的情况 * 1. pageContent1 abcd pageContent2 pageContent3 * 2. pageContent1 pageContent2 abcd pageContent4 * 3. pageContent1 pageContent2 abcd * 4. pageContent1 abcd * 5. pageContent1 abcd pageContent2 * 6. abcd * 7. abcd pageContent * 8. abcd pageContent .. 14 */ if(tag.getStartIndex() == pageBeginIndex && tag.getEndIndex() > pageEndIndex) { // 原来的情况:pageContent1 abcd pageContent2 pageContent3 // 分页之后的情况:abcd // 补齐标签:abcd page = page + tag.getEndTag(); } else if(tag.getEndIndex() + tag.getEndTag().length() - 1 == pageEndIndex && tag.getStartIndex() < pageBeginIndex) { // 原来的情况:pageContent1 pageContent2 abcd pageContent4 // 分页之后的情况:abcd // 补齐标签:abcd page = tag.getStartTag() + page; } else { if(tag.getStartIndex() < pageBeginIndex && tag.getEndIndex() < pageBeginIndex) { // 原来的情况: pageContent1 pageContent2 abcd // 分页之后的情况:abcd // 补齐标签:不需要 // page = page; } else if(tag.getStartIndex() < pageBeginIndex && tag.getEndIndex() > pageBeginIndex && tag.getEndIndex() < pageEndIndex) { // 原来的情况: pageContent1 abcd // 分页之后的情况:abcd // 补齐标签:abcd page = tag.getStartTag() + page; } else if(tag.getStartIndex() < pageBeginIndex && tag.getEndIndex() > pageEndIndex) { // 原来的情况: pageContent1 abcd pageContent2 // 分页之后的情况:abcd // 补齐标签:abcd page = tag.getStartTag() + page + tag.getEndTag(); } else if(tag.getStartIndex() > pageBeginIndex && tag.getEndIndex() < pageEndIndex) { // 原来的情况:abcd // 分页之后的情况:abcd // 补齐标签:不需要 // page = page; } else if(tag.getStartIndex() > pageBeginIndex && tag.getStartIndex() < pageEndIndex && tag.getEndIndex() > pageEndIndex) { // 原来的情况:abcd pageContent // 分页之后的情况:abcd // 补齐标签:abcd page = page + tag.getEndTag(); } else if(tag.getStartIndex() > pageEndIndex) { // 原来的情况:abcd pageContent .. // 分页之后的情况:abcd // 补齐标签:不需要 // page = page; } else { // 不需要补齐 // page = page; } } } compPageText[i] = page; } return compPageText; } /** * 方法说明:获取文本中标签列表 * List * @param text * @return * * @author fisher */ @SuppressWarnings("unchecked") public List getBracketList(String text) { if(text == null || "".equals(text)) return null; char[] textCharArr = text.toCharArray(); List list = new ArrayList(); int lenght = text.length(); int rightBracketIndex, rightSlashIndex; char c; String startTag, endTag; Tag tag; for(int i = 0; i < lenght;) { c = textCharArr[i]; // 包含 '<', 即为标签开始的标志(因为Html源码中只有会将用户手工输入的'<'和'>'转正转义符, // 所以当遇到'<',说明为标签开始) if(isLeftBracket(c)) { rightBracketIndex = getNextRightBracket(text, i); rightSlashIndex = getNextRightSlash(text, i); if(rightBracketIndex == -1) { i = lenght; break; } // if(rightSlashIndex != -1 && (rightSlashIndex + 1) == rightBracketIndex) i = rightBracketIndex + 1; // else if(rightSlashIndex != -1 && (rightSlashIndex - 1) == i) i = rightBracketIndex + 1; // else if(rightSlashIndex == -1 || rightSlashIndex > rightBracketIndex) { tag = new Tag(); startTag = text.substring(i, rightBracketIndex + 1); endTag = getEndTag(startTag); tag.setStartTag(startTag); tag.setEndTag(endTag); tag.setStartIndex(i); tag.setEndIndex(getFirstEndTag(text, endTag, i)); list.add(tag); i = rightBracketIndex + 1; } else i = rightBracketIndex + 1; } else { ++i; } } return list; } /** * 方法说明:返回改文本去除标签之后的虚拟下标值Map * Map key:虚拟的下标index(去除标签) value:正式下标index * 例如:text:小天后林依晨 广告戏剧邀约不断,首次发片成绩更是亮眼 * key(提供给分页使用的下标值) value(文本中对应的真实下标值) * 0 0 * 1 1 * 5 2 * 6 19 * 4 20 * ... ... * @param text * 初始化文本文件 * @return * * @author fisher */ @SuppressWarnings("unchecked") public Map getVirtualIndex(String text) { if(text == null || "".equals(text)) return null; char[] textCharArr = text.toCharArray(); int lenght = text.length(); Map indexMap = new HashMap(); char c; int rightBracketIndex, rightSlashIndex, semicolonIndex; for(int i = 0, j = 0; i < lenght;) { c = textCharArr[i]; if(isLeftBracket(c)) { // 包含 '<' rightBracketIndex = getNextRightBracket(text, i); rightSlashIndex = getNextRightSlash(text, i); if(rightBracketIndex == -1) { i = lenght; break; } // if(rightSlashIndex != -1 && (rightSlashIndex + 1) == rightBracketIndex) i = rightBracketIndex + 1; // else if(rightSlashIndex != -1 && (rightSlashIndex - 1) == i) i = rightBracketIndex + 1; // else if(rightSlashIndex == -1 || rightSlashIndex > rightBracketIndex) i = rightBracketIndex + 1; else i = rightBracketIndex + 1; } else { ++i; } if(i <= lenght && !isBracket(textCharArr[i - 1])) { indexMap.put(j, i - 1); ++j; } } return indexMap; } /** * 方法说明验证字符是否为'<'或者'>' * * @param s * @return * * @author fisher */ public boolean isBracket(char c) { return c == '<' || c == '>'; } /** * 方法说明:验证字符是否为'<' * * @param s * @return * * @author fisher */ public boolean isLeftBracket(char c) { return c == '<'; } /** * 方法说明:验证字符是否为'>' * * @param s * @return * * @author fisher */ public boolean isRightBracket(char c) { return c == '>'; } /** * 方法说明:验证字符是否为'&' * * @param s * @return * * @author fisher */ public boolean isAttend(char c) { return c == '&'; } /** * 方法说明:从beginIndex开始,第一个endTag的下标 * * @param text * @param beginIndex * @return * 包含,返回下标;否则返回-1 * @author fisher */ public int getFirstEndTag(String text, String endTag, int beginIndex) { String rightText = text.substring(beginIndex); int index = rightText.indexOf(endTag); if(index == -1) return -1; return beginIndex + index; } /** * 方法说明:输入开始标签,返回结束标签字符串 * 例如:输入,返回 * @param text * @param beginIndex * @return * * @author fisher */ public String getEndTag(String startTag) { int index = startTag.indexOf(" "); String tag; if(index != -1) tag = startTag.substring(1, index); else tag = startTag.substring(1, startTag.length() - 1); return "" + tag + ">"; } /** * 方法说明:获取从beginIndex开始的第一个">"的下标 * * @param text * @param beginIndex * @return * 包含,返回下标;否则返回-1 * @author fisher */ public int getNextRightBracket(String text, int beginIndex) { String rightText = text.substring(beginIndex); int index = rightText.indexOf(">"); if(index == -1) return -1; return beginIndex + index; } /** * 方法说明:获取从beginIndex开始的字符“/”的下标 * @param text * @param beginIndex * @return * 包含,返回下标;否则返回-1 * @author fisher */ public int getNextRightSlash(String text, int beginIndex) { String rightText = text.substring(beginIndex); int index = rightText.indexOf("/"); if(index == -1) return -1; return beginIndex + index; } /** * 方法说明:获取从beginIndex开始的字符“;”的下标 * @param text * @param beginIndex * @return * 包含,返回下标;否则返回-1 * @author fisher */ public int getNextRightSemicolon(String text, int beginIndex) { String rightText = text.substring(beginIndex); int index = rightText.indexOf(";"); if(index == -1) return -1; return beginIndex + index; } /** * 方法说明:去除Html标签 * * @param text * @return * * @author fisher */ public String filterHtmlTag(String text) { String tempText = text.replaceAll("};", "").replaceAll( "<[^>]*>", ""); tempText = tempText.replaceAll("[(/>)<]", ""); return tempText; } public String filterBracket(String text) { return text.replaceAll("<*>", ""); } }
|