Java處理字符串搜索嵌套結(jié)構(gòu)的方法
在用Java分析HTML文本時(shí),如果要取出有嵌套結(jié)構(gòu)的節(jié)點(diǎn)之間的內(nèi)容,不能直接用正則表達(dá)式來(lái)處理,因?yàn)镴ava所帶的正則表達(dá)式不支持嵌套結(jié)構(gòu)的描述,雖然Perl、.Net、PHP可以支持。這時(shí)可以先用正則表達(dá)式找出節(jié)點(diǎn)在字符串中的位置,然后對(duì)節(jié)點(diǎn)進(jìn)行匹配處理,取出匹配節(jié)點(diǎn)之間的內(nèi)容,實(shí)現(xiàn)對(duì)嵌套結(jié)構(gòu)的處理。
例如要從
- <pre name="code" class="java">data=<div><div>abcd<div></div><form>
- <input type='button' value='submit'/></form></div></div><div>1234</div>
中取出<div></div>之間的內(nèi)容,希望返回兩個(gè)字符串
- <pre name="code" class="java"><div>abcd<div></div><form>
- <input type='button' value='submit'/></form></div><pre name="code" class="html">和1234。
源代碼如下:
為了記錄節(jié)點(diǎn)在字符串中的值和位置,先定義一個(gè)類,保存這些信息:
- public class Tag {
- public Tag(String value, int beginPos, int endPos) {
- super();
- this.value = value;
- this.beginPos = beginPos;
- this.endPos = endPos;
- }
- private String value;
- private int beginPos;
- private int endPos;
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- public int getBeginPos() {
- return beginPos;
- }
- public void setBeginPos(int beginPos) {
- this.beginPos = beginPos;
- }
- public int getEndPos() {
- return endPos;
- }
- public void setEndPos(int endPos) {
- this.endPos = endPos;
- }
- }
從字符串中獲取節(jié)點(diǎn)之間內(nèi)容的函數(shù)如下:
- /**
- * 獲取字符串之間的內(nèi)容,如果包含嵌套,則返回最外層嵌套內(nèi)容
- *
- * @param data
- * @param stag 起始節(jié)點(diǎn)串
- * @param etag 結(jié)束節(jié)點(diǎn)串
- * @return
- */
- public List<String> get(String data,String stag, String etag){
- // 存放起始節(jié)點(diǎn),用于和結(jié)束節(jié)點(diǎn)匹配
- Stack<Tag> work = new Stack<Tag>();
- // 保存所有起始和結(jié)束節(jié)點(diǎn)
- List<Tag> allTags = new ArrayList<Tag>();
- // 在元字符前加轉(zhuǎn)義符
- String nstag = stag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1");
- String netag = etag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1");
- String reg = "((?:"+nstag+")|(?:"+netag+"))";
- Pattern p = Pattern.compile(reg, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
- Matcher m = p.matcher(data);
- while(m.find()){
- Tag tag = new Tag(m.group(0),m.start(),m.end());
- allTags.add(tag);
- }
- // 保存開始結(jié)束節(jié)點(diǎn)之間的內(nèi)容,不含節(jié)點(diǎn)
- List<String> result = new ArrayList<String>();
- for(Tag t : allTags){
- if (stag.equalsIgnoreCase(t.getValue())){
- work.push(t);
- }else if(etag.equalsIgnoreCase(t.getValue())){
- // 如果棧已空,則表示不匹配
- if (work.empty()){
- throw new RuntimeException("pos "+t.getBeginPos()+" tag not match start tag.");
- }
- Tag otag = work.pop();
- // 如果棧為空,則匹配
- if (work.empty()){
- String sub = data.substring(otag.getEndPos(), t.getBeginPos());
- result.add(sub);
- }
- }
- }
- // 如果此時(shí)棧不空,則有不匹配發(fā)生
- if (!work.empty()){
- Tag t = work.pop();
- throw new RuntimeException("tag "+t.getValue()+ "not match.");
- }
- return result;
- }
函數(shù)返回節(jié)點(diǎn)之間內(nèi)容串組成的列表。
例如 調(diào)用 get(data,"<div>", "</div>") 返回含有兩個(gè)元素的列表,元素分別為
- <div>abcd<div></div><form><input type='button' value='>'/></form></div>, 1234
需要注意的是如果節(jié)點(diǎn)含有正則表達(dá)式的元字符,需要在元字符前加轉(zhuǎn)義符\\,源代碼中第16,17行實(shí)現(xiàn)此功能。
原文鏈接:http://blog.csdn.net/indexchen/article/details/7236754
【編輯推薦】