OSDN Git Service

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