View Javadoc
1   package com.github.mygreen.cellformatter.tokenizer;
2   
3   import java.util.LinkedList;
4   
5   import com.github.mygreen.cellformatter.lang.Utils;
6   
7   
8   /**
9    * カスタム定義の書式をトークンに分割する。
10   * @author T.TSUCHIE
11   *
12   */
13  public class CustomFormatTokenizer {
14      
15      /**
16       * 書式をトークンに分割する。
17       * @param pattern Excelの書式
18       * @return
19       */
20      public TokenStore parse(final String pattern) {
21          
22          final TokenStoretter/tokenizer/TokenStore.html#TokenStore">TokenStore store = new TokenStore();
23          if(Utils.isEmpty(pattern)) {
24              return store;
25          }
26          
27          splitToken(store, pattern);
28          return store;
29      }
30      
31      private void splitToken(final TokenStore store, final String pattern) {
32          
33          // 解析時の途中の文字を一時的に補完しておく。
34          final LinkedList<String> stack = new LinkedList<String>();
35          
36          final int length = pattern.length();
37          for(int i=0; i < length; i++) {
38              final char c = pattern.charAt(i);
39              
40              if(StackUtils.equalsAnyTopElement(stack, Token.STR_ESCAPES)) {
41                  
42                  // スタックの一番上がエスケープの文字だが、文字列の囲み文字(")の終了の場合は、文字列として追加する
43                  if(c == '"' && StackUtils.equalsBottomElement(stack, "\"")) {
44                      store.add(Token.word(StackUtils.popupAndConcat(stack) + c));
45                      continue;
46                  }
47                  // スタックの一番上がエスケープ文字の場合でかつ、括弧や文字列などの囲み文字の中の場合は、通常の文字として扱う。
48                  if(StackUtils.equalsAnyBottomElement(stack, new String[]{"[", "\""})) {
49                      stack.push(String.valueOf(c));
50                      
51                  } else {
52                      // エスケープ文字として分割する。
53                      final String escapedChar = StackUtils.popup(stack);
54                      final String concatStr = StackUtils.popupAndConcat(stack);
55                      if(concatStr.length() >= 1) {
56                          // エスケープ文字以前の文字を追加する。
57                          store.add(Token.factor(concatStr));
58                      }
59                      
60                      store.add(Token.escapedChar(escapedChar + c));
61                      
62                  }
63                  
64                  continue;
65              }
66              
67              if(c == '"') {
68                  
69                  if(StackUtils.equalsBottomElement(stack, "\"")) {
70                      // 文字列の囲み文字'"'の終わりの場合、文字列として追加する。
71                      store.add(Token.word(StackUtils.popupAndConcat(stack) + c));
72                      
73                  } else if(!stack.isEmpty()) {
74                      // 文字列の引用符で始まらず、既に文字が入っている場合は、既存のものを取り出し分割する。
75                      // 既存のものはFactorとする。
76                      store.add(Token.factor(StackUtils.popupAndConcat(stack)));
77                      stack.push(String.valueOf(c));
78                      
79                  } else {
80                      // 文字列の開始の場合
81                      stack.push(String.valueOf(c));
82                      
83                  }
84                  
85              } else if(c == '[') {
86                  if(!stack.isEmpty() && !StackUtils.equalsBottomElement(stack, "\"")) {
87                      // 文字列の引用符の中ではなく、既に文字が入っている場合は、既存のものを取り出し分割する。
88                      // 既存のものはFactorとする。
89                      store.add(Token.factor(StackUtils.popupAndConcat(stack)));
90                  }
91                  
92                  stack.push(String.valueOf(c));
93                  
94              } else if(c == ']') {
95                  
96                  if(StackUtils.equalsBottomElement(stack, "[")) {
97                      // 条件の終わりの場合
98                      store.add(Token.condition(StackUtils.popupAndConcat(stack) + c));
99                      
100                 } else {
101                     stack.push(String.valueOf(c));
102                 }
103                 
104             } else if(c == ';') {
105                 
106                 if(!stack.isEmpty()) {
107                     // 既に文字が入っている場合は、既存のものを取り出し分割する。
108                     store.add(Token.factor(StackUtils.popupAndConcat(stack)));
109                 }
110                 
111                 store.add(Token.SYMBOL_SEMI_COLON);
112                 
113             } else if(c == '_') {
114                 if(StackUtils.equalsBottomElement(stack, "\"")) {
115                     // 文字列の中の場合の場合は、文字列として処理する。
116                     stack.push(String.valueOf(c));
117                     
118                     continue;
119                 }
120                 
121                 // スタックに文字がある場合、既存のものを取り出し分割する。
122                 if(!stack.isEmpty()) {
123                     store.add(Token.factor(StackUtils.popupAndConcat(stack)));
124                     
125                 }
126                 
127                 // 次に続く1文字を取得する
128                 StringBuilder next = new StringBuilder();
129                 if(i + 1 < length) {
130                     i++;
131                     final char c2 = pattern.charAt(i);
132                     next.append(c2);
133                     
134                     if(c2 == '\\') {
135                         if(i + 1 < length) {
136                             i++;
137                             i++;
138                             final char c3 = pattern.charAt(i);
139                             next.append(c3);
140                         }
141                     }
142                     
143                     store.add(Token.underscore(c + next.toString()));
144                     
145                 } else {
146                     store.add(Token.factor(String.valueOf(c)));
147                 }
148                 
149                 
150             } else if(c == '*') {
151                 
152                 if(StackUtils.equalsBottomElement(stack, "\"")) {
153                     // 文字列の中の場合の場合は、文字列として処理する。
154                     stack.push(String.valueOf(c));
155                     
156                     continue;
157                 }
158                 
159                 // スタックに文字がある場合、既存のものを取り出し分割する。
160                 if(!stack.isEmpty()) {
161                     store.add(Token.factor(StackUtils.popupAndConcat(stack)));
162                     
163                 }
164                 
165                 // 次に続く1文字を取得する
166                 StringBuilder next = new StringBuilder();
167                 if(i + 1 < length) {
168                     i++;
169                     final char c2 = pattern.charAt(i);
170                     next.append(c2);
171                     
172                     if(c2 == '\\') {
173                         if(i + 1 < length) {
174                             i++;
175                             i++;
176                             final char c3 = pattern.charAt(i);
177                             next.append(c3);
178                         }
179                     }
180                     
181                     store.add(Token.asterisk(c + next.toString()));
182                     
183                 } else {
184                     store.add(Token.factor(String.valueOf(c)));
185                 }
186                 
187             } else {
188                 
189                 stack.push(String.valueOf(c));
190             }
191             
192             
193         }
194         
195         if(!stack.isEmpty()) {
196             store.add(Token.factor(StackUtils.popupAndConcat(stack)));
197         }
198         
199     }
200     
201 }