1. 程式人生 > >後綴表達式

後綴表達式

space 分配 出棧 後綴 row sign matcher rtt 沒有

  我經常不厭其煩地向開發人員強調數據結構的重要性,也經常和團隊分享一些常見算法。也許是大家寫慣了業務代碼,往往對數據結構的知識並不太在意。可不是嘛,只需要玩轉QUID就能解決90%以上的問題,還費腦細胞學習基礎知識幹什麽?當然,所有人都會回答“基礎知識很重要,數據結構很重要”。然而,當你發現工作幾年的開發人員甚至不知道Array和List的區別時,也許會覺得他們當初是在說謊。這是真的,我發現大部分人不知道還有個鏈表叫“循環鏈表”。

  下面講述的是多年前的故事。

  表格曾是我們在JSP頁面常用的布局方式,碰到合並單元格時會不停的使用collspan和rowspan。為了簡化操作,我規劃了一個布局管理器,用一個字符串代替表格布局。大概長這個樣子:

layout="3;C2(bop1, bop2),C3(bop3, bop4)" ,layout是自定義標簽屬性,bop對應布局中的一個細粒度組件,3表示默認3列布局,C2和C3分別表示合並2個和3個單元格。連起來的意思就是,當前容器默認3列布局,其中bop1和bop2需要占兩列,bop3和bop4需要占3列,其余組件占1列。還可以進行行合並:layout="3;R2(C2(bop1, bop2)),C3(bop3, bop4)",表示bop1, bop2合並兩列後再合並兩行。當然,你可以寫的更加隨意,只要有意義即可,如:layout="3;R2(C2(bop1)),R2(C2(bop2)),C3(bop3, bop4)",layout="4;C2(bop1),C2(bop2),C3(bop3)"。

  當時我把這個任務分配給一個工作了4年左右開發人員,並告訴他去看看後綴表達式,並順便看看解析器模式。

  兩天後我得到了任務完成的答復,然後開始review。

  這下好玩了,布局管理器變成了這樣:layout="3;C2:bop1,bop2;C3:bop3;bop4"。似乎沒那麽壞,至少還能工作,但看起來沒那麽直觀了,似乎也不能更加隨意。私自更改設計的原因很簡單——這樣可以更容易使用split,哈,貌似沒有理解如何使用數據結構。

  後來使用後綴表達式重寫了實現。這實際上是棧結構的典型應用,遍歷字符串,根據各種符號為節點,不斷入棧出棧。具體過程如下:

  1. 刨除前面的默認列數

  2. cellMap存儲最終解析結果,key對應bop名稱,value對應布局,即合並幾行幾列;

stack是表達式棧,存儲R1,C1,R2,C2這類xspan表達式;atom是字符串,代表xspan表達式RX,CX或bop

  3. 遍歷布局管理器字符串

  3.1. 遇到數字或字母直接並入atom

  3.2 遇到左括號,將atom壓入stack,清空atom

  3.3 遇到逗號, 如果stack不為空, 將stack中的所有xspan表達式代表的含義賦予bop, 將bop壓入cellMap,清空atom; 如果stack為空, 清空atom

  3.4 遇到右括號, 將stack中的所有xspan表達式代表的含義賦予bop, 將bop壓入cellMap, 從stack彈出一項.

  4.布局管理器字符串遍歷結束,cellMap是最終結果

  以R2(C2(bop1, bop2)),C3(bop3, bop4)為例:

技術分享

 1.遍歷字符串,atom="R2"

  2.遇到"(",stack.push(atom),atom="", stack棧頂元素為"R2"

  3.繼續遍歷字符串,atom="C2"

  4.遇到"(",stack.push(atom),atom="", stack棧頂元素為"C2",第二個元素為"R2"

  5.繼續遍歷字符串,atom="bop1"

  6.遇到",",cellMap.put("bop1", "C2,R2"),atom=""

  7.繼續遍歷字符串,atom="bop2"

  8.遇到")",cellMap.put("bop2", Cell.C2),stack.pop(), stack中C2出棧,R2升到棧頂

  9.遇到")",cellMap.put("bop2", Cell.R2),stack.pop(), stack中R2出棧,stack為空

  10.遇到",",此時stack為空,所以atom=""

  11.繼續遍歷字符串,atom="C3"

  12.遇到"(",stack.push(atom),atom="", stack棧頂元素為"C3"

  13.繼續遍歷字符串,atom="bop3"

  14.遇到",",cellMap.put("bop3", "C3"),atom=""

  15.繼續遍歷字符串,atom="bop4"

  16.遇到")",cellMap.put("bop4", "C3"),stack.pop(), stack中C3出棧,stack為空

  17.遍歷結束,最終得到cellMap

代碼示例:

  1 /**
  2  * 
  3  * 布局管理器表達式解釋器
  4  */
  5 public class Interpreter {
  6     
  7     /*
  8      * 布局管理器表達式
  9      * 布局管理器表達式示例:
 10      *     1.  3;C2(bop1, bop2),C3(bop3, bop4);
 11      *     默認3列,bop1,bop2合並2列,bop3,bop4合並3列;
 12      *  2.  4;R2(C2(bop1, bop2)),C3(bop3, bop4) 
 13      *  默認4列,bop1,bop2合並2列2行,bop3,bop4合並3列;
 14      *  3.  粗粒度組件布局管理器表達式類似: C2(boid1, boid2).
 15      */
 16     private String layoutStr;
 17     private int columns;    //布局的列數
 18     /*
 19      * key : vcSign, value : formCell
 20      * vcSign:如果是細粒度組件,vcSign表示細粒度組件標簽的bind屬性;
 21      * 如果是粗粒度組件,vcSign表示粗粒度組件標簽的id屬性。
 22      */
 23     private Map<String, Cell> cellMap = new HashMap<String, Cell>();
 24     
 25     private final String EXPRESSION_SPLIT = ";";
 26     private final char FC_SPLIT = ‘,‘;
 27     private final char LEFT_BRACKET = ‘(‘;
 28     private final char RIGHT_BRACKET = ‘)‘;
 29     
 30     /**
 31      * @param layoutStr      布局管理器表達式
 32      * @param defColumns     默認列數
 33      */
 34     public Interpreter(String layoutStr, int defColumns) {
 35         this.layoutStr = StringUtils.removeAllSpace(layoutStr);
 36         this.columns = defColumns;
 37     }
 38 
 39     /**
 40      * 解析布局管理器表達式.
 41      */
 42     public void interpret() {
 43         if(StringUtils.isEmpty(getLayoutStr())) 
 44             return;
 45         
 46         String[] layoutSplit = StringUtils.split(getLayoutStr(), EXPRESSION_SPLIT);
 47         if(StringUtils.isEmpty(layoutSplit))
 48             return;
 49         
 50         interpertColumns(layoutSplit[0]);
 51         for(String str : layoutSplit) {
 52             if(StringUtils.isEmpty(str) || MatcherUtil.isNumber(str))
 53                 continue;
 54             
 55             interpertFormCell(str);
 56         }
 57     }
 58     
 59     /**
 60      * 解析默認列數
 61      * @param str    布局管理器劃分的總列數
 62      */
 63     private void interpertColumns(String str) {
 64         Integer columns = StringUtils.convertToInteger(str);
 65         if(columns != null && columns > 0)
 66             setColumns(columns);
 67     }
 68     
 69     /**
 70      * 構造每個bop的布局樣式
 71      * R2(C2(bop1, bop2)) 或  R2(bop3, C2(bop1, bop2))
 72      * <li>1. 遍歷表達式, 解析子元素;
 73      * <li>2. 遇到左括號,將R2, C2 表達式壓入表達式棧頂;
 74      * <li>3. 遇到逗號, 如果棧不為空, 將棧中的所有表達式代表的含義賦予bop, 將bop壓入cellMap; 如果棧為空, 直接略過;
 75      * <li>4. 遇到右括號, 將棧中的所有表達式代表的含義賦予bop, 將bop壓入cellMap, 從表達式棧頂彈出一項.
 76      * @param str
 77      */
 78     private void interpertFormCell(String str) {
 79         //表達式棧, 存儲 R1, C1, R2, C2等合並單元格的表達式
 80         Stack<String> stack = new Stack<String>();
 81         
 82         //表達式的元素
 83         String atom = "";
 84         //遍歷表達式, 解析子元素
 85         for(int i = 0, length = str.length(); i < length; i++) {
 86             char ch = str.charAt(i);
 87             //遇到左括號,將R2, C2 表達式壓入表達式棧頂
 88             if(LEFT_BRACKET == ch) {
 89                 stack.push(atom);
 90                 atom = "";
 91             }
 92             //遇到逗號, 如果棧不為空, 將棧中的所有表達式代表的含義賦予bop, 將bop壓入cellMap; 
 93             //如果棧為空, 直接略過;
 94             else if(FC_SPLIT == ch) {
 95                 if(ContainerUtil.isNotNull(stack))
 96                     formatCell(atom, stack);
 97                 atom = "";
 98             }
 99             //遇到右括號, 將棧中的所有表達式代表的含義賦予bop, 將bop壓入cellMap, 從表達式棧頂彈出一項
100             else if(RIGHT_BRACKET == ch) {
101                 if(StringUtils.isNotEmpty(atom))
102                     formatCell(atom, stack);
103                 stack.pop();105             }
106             else {
107                 atom += ch;
108             }
109         }
110     }
111     
112     /**
113      * 將bop壓入cellMap
114      * @param vcSign
115      * @param stack 表達式棧
116      */
117     private void formatCell(String vcSign, Stack<String> stack) {
118         Cell cell = getCell(vcSign);
119         
120         Iterator<String> itr = stack.iterator();
121         while(itr.hasNext()) {
122             String expression = itr.next();
123             if(isCELLSPAN(expression)) 
124                 cell.setCollSpan(getCallSpan(expression));
125             else if(isROWSPAN(expression)) 
126                 cell.setRowSpan(getRowSpan(expression));
127         }        
128         
129         cellMap.put(vcSign, cell);
130     }
131     
132     private int getCallSpan(String expression) {
133         int collSpan = Integer.parseInt(expression.toUpperCase().replace("C", ""));
134         return collSpan > getColumns() ? getColumns() : collSpan;
135     }
136     
137     private int getRowSpan(String expression) {
138         return Integer.parseInt(expression.toUpperCase().replace("R", ""));
139     }
140 
141     private Cell getCell(String atom) {
142         Cell cell = cellMap.get(atom);
143         return cell == null ? new Cell() : cell;
144     }
145     
146     private boolean isCELLSPAN(String str) {
147         return MatcherUtil.isAllMatch(str, "^[C|c]-?\\d+$");
148     }
149     
150     private boolean isROWSPAN(String str) {
151         return MatcherUtil.isAllMatch(str, "^[R|r]-?\\d+$");
152     }
153     
154     public int getColumns() {
155         return this.columns;
156     }
157 
158     public void setColumns(int columns) {
159         this.columns = columns;
160     }
161 
162     public String getLayoutStr() {
163         return layoutStr;
164     }
165 
166     public void setLayoutStr(String layoutStr) {
167         this.layoutStr = layoutStr;
168     }
169 
170     public Map<String, Cell> getCellMap() {
171         return cellMap;
172     }
173 
174     public void setCellMap(Map<String, Cell> cellMap) {
175         this.cellMap = cellMap;
176     }


作者:我是8位的

出處:http://www.cnblogs.com/bigmonkey

本文以學習、研究和分享為主,如需轉載,請聯系本人,標明作者和出處,非商業用途!

後綴表達式