OSDN Git Service

JSON入出力部をJovsonzプロジェクトに分離。
[jindolf/Jindolf.git] / src / main / java / jp / sourceforge / jindolf / RegexPattern.java
1 /*
2  * Regex pattern
3  *
4  * License : The MIT License
5  * Copyright(c) 2008 olyutorskii
6  */
7
8 package jp.sourceforge.jindolf;
9
10 import java.util.regex.Pattern;
11 import java.util.regex.PatternSyntaxException;
12 import jp.sourceforge.jovsonz.JsBoolean;
13 import jp.sourceforge.jovsonz.JsObject;
14 import jp.sourceforge.jovsonz.JsPair;
15 import jp.sourceforge.jovsonz.JsString;
16 import jp.sourceforge.jovsonz.JsValue;
17
18 /**
19  * 正規表現。
20  */
21 public class RegexPattern{
22
23     /** 英字大小無視指定フラグ。 */
24     public static final int IGNORECASEFLAG =
25             0x00000000 | Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE;
26     private static final String REGEX_DELIM = "[\\s\u3000]+"; // 空白(全角含)
27     private static final String REGEX_CHAR = ".?+*\\$(|)[]{}^-&";
28
29
30     private final String editSource;
31     private final boolean isRegex;
32     private final Pattern pattern;
33     private final String comment;
34
35
36     /**
37      * コンストラクタ。
38      *
39      * @param editSource リテラル文字列または正規表現
40      * @param isRegex 指定文字列が正規表現ならtrue。リテラルならfalse
41      * @param flag 正規表現フラグ
42      * @param comment コメント
43      * @throws java.util.regex.PatternSyntaxException 正規表現がおかしい
44      */
45     public RegexPattern(String editSource,
46                         boolean isRegex,
47                         int flag,
48                         String comment)
49             throws PatternSyntaxException{
50         super();
51         if(editSource == null) throw new NullPointerException();
52
53         this.isRegex    = isRegex;
54         if(comment != null) this.comment = comment;
55         else                this.comment = "";
56
57         String regexExpr;
58         if(this.isRegex){
59             this.editSource = editSource;
60             regexExpr = this.editSource;
61         }else{
62             String newSource = "";
63             regexExpr = "";
64
65             String[] tokens = editSource.split(REGEX_DELIM);
66             for(String token : tokens){
67                 if(token == null || token.length() <= 0) continue;
68
69                 if(newSource.length() <= 0) newSource  =       token;
70                 else                        newSource += " " + token;
71
72                 String quoted = "(?:" + quote(token) + ")";
73                 if(regexExpr.length() <= 0) regexExpr  =       quoted;
74                 else                        regexExpr += "|" + quoted;
75             }
76
77             this.editSource = newSource;
78         }
79
80         this.pattern = Pattern.compile(regexExpr, flag);
81
82         return;
83     }
84
85     /**
86      * コンストラクタ。
87      *
88      * @param editSource リテラル文字列または正規表現
89      * @param isRegex 指定文字列が正規表現ならtrue。リテラルならfalse
90      * @param flag 正規表現フラグ
91      * @throws java.util.regex.PatternSyntaxException 正規表現がおかしい
92      */
93     public RegexPattern(String editSource,
94                         boolean isRegex,
95                         int flag )
96             throws PatternSyntaxException{
97         this(editSource, isRegex, flag, " ");
98         return;
99     }
100
101
102     /**
103      * 正規表現とまぎらわしい字を含むか判定する。
104      * @param seq 文字列
105      * @return 紛らわしい字を含むならtrue
106      */
107     public static boolean hasRegexChar(CharSequence seq){
108         int length = seq.length();
109         for(int pt = 0; pt < length; pt++){
110             char ch = seq.charAt(pt);
111             if(REGEX_CHAR.indexOf(ch) >= 0) return true;
112         }
113         return false;
114     }
115
116     /**
117      * 任意の文字列を必要に応じて正規表現シーケンス化する。
118      * @param text 文字列
119      * @return 引数と同じ内容の正規表現。必要がなければ引数そのまま
120      */
121     public static String quote(String text){
122         if(hasRegexChar(text)){
123             return Pattern.quote(text);
124         }
125         return text;
126     }
127
128     /**
129      * JSON形式に変換する。
130      * @param regex 正規表現
131      * @return JSON Object
132      */
133     public static JsObject encodeJson(RegexPattern regex){
134         JsObject result = new JsObject();
135
136         int regexFlag = regex.getRegexFlag();
137         boolean flagDotall     = (regexFlag & Pattern.DOTALL)           != 0;
138         boolean flagMultiline  = (regexFlag & Pattern.MULTILINE)        != 0;
139         boolean flagIgnoreCase = (regexFlag & IGNORECASEFLAG) != 0;
140
141         JsPair source     = new JsPair("source",     regex.getEditSource());
142         JsPair isRegex    = new JsPair("isRegex",    regex.isRegex());
143         JsPair dotall     = new JsPair("dotall",     flagDotall);
144         JsPair multiline  = new JsPair("multiline",  flagMultiline);
145         JsPair ignorecase = new JsPair("ignorecase", flagIgnoreCase);
146         JsPair comment    = new JsPair("comment",    regex.getComment());
147
148         result.putPair(source);
149         result.putPair(isRegex);
150         result.putPair(dotall);
151         result.putPair(multiline);
152         result.putPair(ignorecase);
153         result.putPair(comment);
154
155         return result;
156     }
157
158     /**
159      * JSON形式から復元する。
160      * @param object JSON Object
161      * @return 正規表現
162      */
163     public static RegexPattern decodeJson(JsObject object){
164         JsValue value;
165
166         String source;
167         value = object.getValue("source");
168         if(value instanceof JsString){
169             source = ((JsString)value).toRawString();
170         }else{
171             source = "";
172         }
173
174         boolean isRegex;
175         value = object.getValue("isRegex");
176         if(value instanceof JsBoolean){
177             isRegex = ((JsBoolean)value).booleanValue();
178         }else{
179             isRegex = false;
180         }
181
182         int regexFlag = 0x00000000;
183         value = object.getValue("dotall");
184         if(value instanceof JsBoolean){
185             if(((JsBoolean)value).isTrue()){
186                 regexFlag |= Pattern.DOTALL;
187             }
188         }
189         value = object.getValue("multiline");
190         if(value instanceof JsBoolean){
191             if(((JsBoolean)value).isTrue()){
192                 regexFlag |= Pattern.MULTILINE;
193             }
194         }
195         value = object.getValue("ignorecase");
196         if(value instanceof JsBoolean){
197             if(((JsBoolean)value).isTrue()){
198                 regexFlag |= IGNORECASEFLAG;
199             }
200         }
201
202         String comment;
203         value = object.getValue("comment");
204         if(value instanceof JsString){
205             comment = ((JsString)value).toRawString();
206         }else{
207             comment = "";
208         }
209
210         RegexPattern result =
211                 new RegexPattern(source, isRegex, regexFlag, comment);
212
213         return result;
214     }
215
216
217     /**
218      * 元の入力文字列を返す。
219      * @return 入力文字列
220      */
221     public String getEditSource(){
222         return this.editSource;
223     }
224
225     /**
226      * コメントを返す。
227      * @return コメント
228      */
229     public String getComment(){
230         return this.comment;
231     }
232
233     /**
234      * 元の入力文字列が正規表現か否か返す。
235      * @return 正規表現ならtrue
236      */
237     public boolean isRegex(){
238         return this.isRegex;
239     }
240
241     /**
242      * 正規表現フラグを返す。
243      * @return 正規表現フラグ。
244      * @see java.util.regex.Pattern#flags()
245      */
246     public int getRegexFlag(){
247         return this.pattern.flags();
248     }
249
250     /**
251      * コンパイルされた正規表現形式を返す。
252      * @return コンパイルされた正規表現形式
253      */
254     public Pattern getPattern(){
255         return this.pattern;
256     }
257
258     /**
259      * {@inheritDoc}
260      * @return {@inheritDoc}
261      */
262     @Override
263     public String toString(){
264         return this.editSource;
265     }
266
267     /**
268      * {@inheritDoc}
269      * @param obj {@inheritDoc}
270      * @return {@inheritDoc}
271      */
272     @Override
273     public boolean equals(Object obj){
274         if(obj == null){
275             return false;
276         }
277         if( ! (obj instanceof RegexPattern) ){
278             return false;
279         }
280         RegexPattern other = (RegexPattern) obj;
281
282         String thisPattern = this.pattern.pattern();
283         String otherPattern = other.pattern.pattern();
284
285         if( ! thisPattern.equals(otherPattern) ) return false;
286
287         if(this.pattern.flags() != other.pattern.flags()) return false;
288
289         return true;
290     }
291
292     /**
293      * {@inheritDoc}
294      * @return {@inheritDoc}
295      */
296     @Override
297     public int hashCode(){
298         int hash = this.pattern.pattern().hashCode();
299         hash ^= this.pattern.flags();
300         return hash;
301     }
302
303 }