Formatting
[jalview.git] / src / com / stevesoft / pat / Skip.java
1 //\r
2 // This software is now distributed according to\r
3 // the Lesser Gnu Public License.  Please see\r
4 // http://www.gnu.org/copyleft/lesser.txt for\r
5 // the details.\r
6 //    -- Happy Computing!\r
7 //\r
8 package com.stevesoft.pat;\r
9 \r
10 /** This class is used internally to search ahead for some\r
11     optimized Regex objects.  It searches within a String\r
12     for occrences of a given String -- like a more flexible\r
13     version of String.indexOf.\r
14     @see com.stevesoft.pat.Skip2\r
15     @see com.stevesoft.pat.SkipBMH\r
16  */\r
17 public class Skip\r
18 {\r
19   static int mkmask(int c)\r
20   {\r
21     char x = (char) c;\r
22     return~ (CaseMgr.toUpperCase(x) |\r
23              CaseMgr.toLowerCase(x) |\r
24              CaseMgr.toTitleCase(x));\r
25   }\r
26 \r
27   String src;\r
28   int c, mask;\r
29   int offset;\r
30   boolean ign, m1;\r
31   /** Examine a Regex to determine what String it will\r
32       attempt to skip to when searching for patterns.\r
33       Return -1 if we aren't doing this. */\r
34   public static String string(Regex r)\r
35   {\r
36     return r.skipper == null ? null : r.skipper.src;\r
37   }\r
38 \r
39   /** Determine the offset of the String within the pattern\r
40       that we are skipping to. Return -1 if we aren't doing\r
41       this.  */\r
42   public static int offset(Regex r)\r
43   {\r
44     return r.skipper == null ? -1 : r.skipper.offset;\r
45   }\r
46 \r
47   /** Initialize, give it a String to search for, tell it\r
48       whether or not to ignoreCase, and what the offset is\r
49       of the String within the String to be searched. */\r
50   public Skip(String s, boolean ign, int o)\r
51   {\r
52     src = s;\r
53     c = s.charAt(0);\r
54     if (ign)\r
55     {\r
56       mask = mkmask(c);\r
57     }\r
58     else\r
59     {\r
60       mask = 0;\r
61     }\r
62     offset = o;\r
63     this.ign = ign;\r
64     m1 = (s.length() == 1);\r
65   }\r
66 \r
67   /** The same as find(s,0,s.length()) */\r
68   public final int find(StringLike s)\r
69   {\r
70     return find(s, 0, s.length());\r
71   }\r
72 \r
73   static final int min(int a, int b)\r
74   {\r
75     return a < b ? a : b;\r
76   }\r
77 \r
78   /** Searches a given region of text beginning at position start\r
79       and ending at position end for the skip object. */\r
80   public int find(StringLike s, int start, int end)\r
81   {\r
82     if (start > end)\r
83     {\r
84       return -1;\r
85     }\r
86     start += offset;\r
87     int vend = min(s.length() - 1, end + offset);\r
88     if (mask != c)\r
89     {\r
90       for (int i = start; i <= vend; i++)\r
91       {\r
92         if (0 == (s.charAt(i) & mask))\r
93         {\r
94           //if(m1||s.regionMatches(ign,i,src,0,src.length()) )\r
95           if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))\r
96           {\r
97             return i - offset;\r
98           }\r
99         }\r
100       }\r
101     }\r
102     else\r
103     {\r
104       for (int i = start; i <= vend; i++)\r
105       {\r
106         if (c == s.charAt(i))\r
107         {\r
108           //if(m1||s.regionMatches(ign,i,src,0,src.length()) )\r
109           if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))\r
110           {\r
111             return i - offset;\r
112           }\r
113         }\r
114       }\r
115     }\r
116     return -1;\r
117   }\r
118 \r
119   static Skip findSkip(Regex r)\r
120   {\r
121     return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes);\r
122   }\r
123 \r
124   // look for things that can be skipped\r
125   static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc)\r
126   {\r
127     StringBuffer sb = new StringBuffer();\r
128     Skip subsk = null;\r
129     int offset = 0;\r
130     int skipc = -1, skipoff = 0;\r
131     for (; p != null; p = p.next)\r
132     {\r
133       if (p instanceof oneChar)\r
134       {\r
135         skipc = ( (oneChar) p).c;\r
136         skipoff = offset;\r
137       }\r
138       if (p instanceof oneChar && p.next instanceof oneChar)\r
139       {\r
140         Pattern psav = p;\r
141         sb.append( ( (oneChar) p).c);\r
142         while (p.next instanceof oneChar)\r
143         {\r
144           sb.append( ( (oneChar) p.next).c);\r
145           p = p.next;\r
146         }\r
147         String st = sb.toString();\r
148         Skip sk = null;\r
149         if (st.length() > 2)\r
150         {\r
151           sk = new SkipBMH(st, ignoreCase, offset);\r
152         }\r
153         else\r
154         {\r
155           sk = new Skip2(st, ignoreCase, offset);\r
156         }\r
157         if (trnc && st.length() > 2)\r
158         { // chop out a whole string...\r
159           psav.next = new Skipped(st.substring(1));\r
160           psav.next.next = p.next;\r
161           psav.next.parent = p.parent;\r
162         }\r
163         return sk;\r
164       }\r
165       else if (p instanceof Or && ( (Or) p).v.size() == 1\r
166                && ! ( (Or) p).leftForm().equals("(?!")\r
167                && null != (subsk =\r
168                            findSkip( (Pattern) ( (Or) p).v.elementAt(0),\r
169                                     ignoreCase, trnc)))\r
170       {\r
171         subsk.offset += offset;\r
172         return subsk;\r
173       }\r
174       else if (p.minChars().equals(p.maxChars()))\r
175       {\r
176         offset += p.minChars().intValue();\r
177       }\r
178       else\r
179       {\r
180         return skipc < 0 ? null :\r
181             new Skip("" + (char) skipc, ignoreCase, skipoff);\r
182       }\r
183     }\r
184     return null;\r
185   }\r
186 }\r