664c712233900a01d8c0acb14abda7ade85f13b1
[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     static int mkmask(int c) {\r
19         char x = (char)c;\r
20         return ~( CaseMgr.toUpperCase(x) |\r
21             CaseMgr.toLowerCase(x) |\r
22             CaseMgr.toTitleCase(x));\r
23     }\r
24     static { int x = Regex.BackRefOffset; }\r
25     String src;\r
26     int c,mask;\r
27     int offset;\r
28     boolean ign,m1;\r
29     /** Examine a Regex to determine what String it will\r
30         attempt to skip to when searching for patterns.\r
31         Return -1 if we aren't doing this. */\r
32     public static String string(Regex r) {\r
33         return r.skipper == null ? null : r.skipper.src;\r
34     }\r
35     /** Determine the offset of the String within the pattern\r
36         that we are skipping to. Return -1 if we aren't doing\r
37         this.  */\r
38     public static int offset(Regex r) {\r
39         return r.skipper == null ? -1 : r.skipper.offset;\r
40     }\r
41     /** Initialize, give it a String to search for, tell it\r
42         whether or not to ignoreCase, and what the offset is\r
43         of the String within the String to be searched. */\r
44     public Skip(String s,boolean ign,int o) {\r
45         src = s;\r
46         c = s.charAt(0);\r
47         if(ign) {\r
48             mask = mkmask(c);\r
49         } else mask = 0;\r
50         offset = o;\r
51         this.ign = ign;\r
52         m1 = (s.length()==1);\r
53     }\r
54     /** The same as find(s,0,s.length()) */\r
55     public final int find(StringLike s) {\r
56         return find(s,0,s.length());\r
57     }\r
58     static final int min(int a,int b) { return a<b ? a : b; }\r
59     /** Searches a given region of text beginning at position start\r
60         and ending at position end for the skip object. */\r
61     public int find(StringLike s,int start,int end) {\r
62         if(start > end) return -1;\r
63         start += offset;\r
64         int vend = min(s.length()-1,end+offset);\r
65         if(mask != c) {\r
66             for(int i=start;i<=vend;i++)\r
67                 if(0 == (s.charAt(i) & mask))\r
68                     //if(m1||s.regionMatches(ign,i,src,0,src.length()) )\r
69                     if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )\r
70                         return i-offset;\r
71         } else {\r
72             for(int i=start;i<=vend;i++)\r
73                 if(c == s.charAt(i))\r
74                     //if(m1||s.regionMatches(ign,i,src,0,src.length()) )\r
75                     if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )\r
76                         return i-offset;\r
77         }\r
78         return -1;\r
79     }\r
80     static Skip findSkip(Regex r) {\r
81         return findSkip(r.thePattern,r.ignoreCase,!r.dontMatchInQuotes);\r
82     }\r
83     // look for things that can be skipped\r
84     static Skip findSkip(Pattern p,boolean ignoreCase,boolean trnc) {\r
85         StringBuffer sb = new StringBuffer();\r
86         Skip subsk = null;\r
87         int offset = 0;\r
88         int skipc = -1,skipoff=0;\r
89         for(;p != null;p = p.next) {\r
90             if(p instanceof oneChar) {\r
91                 skipc = ((oneChar)p).c;\r
92                 skipoff = offset;\r
93             }\r
94             if(p instanceof oneChar && p.next instanceof oneChar) {\r
95                 Pattern psav = p;\r
96                 sb.append(((oneChar)p).c);\r
97                 while(p.next instanceof oneChar) {\r
98                     sb.append(((oneChar)p.next).c);\r
99                     p = p.next;\r
100                 }\r
101                 String st = sb.toString();\r
102                 char c0 = st.charAt(0), c1 = st.charAt(1);\r
103                 Skip sk=null;\r
104                 if(st.length()>2)\r
105                     sk = new SkipBMH(st,ignoreCase,offset);\r
106                 else\r
107                     sk = new Skip2(st,ignoreCase,offset);\r
108                 if(trnc && st.length()>2) { // chop out a whole string...\r
109                     psav.next = new Skipped(st.substring(1));\r
110                     psav.next.next = p.next;\r
111                     psav.next.parent = p.parent;\r
112                 }\r
113                 return sk;\r
114             } else if(p instanceof Or && ((Or)p).v.size()==1\r
115                     && !((Or)p).leftForm().equals("(?!")\r
116                     && null != (subsk=\r
117                     findSkip( (Pattern)((Or)p).v.elementAt(0),ignoreCase,trnc) )) {\r
118                 subsk.offset += offset;\r
119                 return subsk;\r
120             } else if(p.minChars().equals(p.maxChars())) {\r
121                 offset += p.minChars().intValue();\r
122             } else return skipc < 0 ? null :\r
123                 new Skip(""+(char)skipc,ignoreCase,skipoff);\r
124         }\r
125         return null;\r
126     }\r
127 }\r