001    package railo.runtime.regex;
002    
003    import org.apache.oro.text.regex.MalformedPatternException;
004    import org.apache.oro.text.regex.MatchResult;
005    import org.apache.oro.text.regex.Pattern;
006    import org.apache.oro.text.regex.PatternMatcherInput;
007    import org.apache.oro.text.regex.Perl5Compiler;
008    import org.apache.oro.text.regex.Perl5Matcher;
009    import org.apache.oro.text.regex.Perl5Substitution;
010    import org.apache.oro.text.regex.Util;
011    
012    import railo.commons.collections.HashTable;
013    import railo.runtime.op.Constants;
014    import railo.runtime.type.Array;
015    import railo.runtime.type.ArrayImpl;
016    import railo.runtime.type.Struct;
017    import railo.runtime.type.StructImpl;
018    
019    /**
020     * 
021     */
022    public final class Perl5Util {
023        
024        private static HashTable patterns=new HashTable();
025        
026            /**
027             * return index of the first occurence of the pattern in input text
028             * @param strPattern pattern to search
029             * @param strInput text to search pattern
030             * @param offset 
031             * @param caseSensitive
032             * @return position of the first occurence
033             * @throws MalformedPatternException
034            */
035            public static int indexOf(String strPattern, String strInput, int offset, boolean caseSensitive) throws MalformedPatternException {
036            //Perl5Compiler compiler = new Perl5Compiler();
037            PatternMatcherInput input = new PatternMatcherInput(strInput);
038            Perl5Matcher matcher = new Perl5Matcher();
039            
040            int compileOptions=caseSensitive ? 0 : Perl5Compiler.CASE_INSENSITIVE_MASK;
041            compileOptions+=Perl5Compiler.SINGLELINE_MASK;
042            if(offset < 1) offset = 1;
043            
044            Pattern pattern = getPattern(strPattern,compileOptions);
045            //Pattern pattern = compiler.compile(strPattern,compileOptions);
046            
047    
048            if(offset <= strInput.length()) input.setCurrentOffset(offset - 1);
049            
050            if(offset <= strInput.length() && matcher.contains(input, pattern)) {
051                return matcher.getMatch().beginOffset(0) + 1; 
052            }
053            return 0;
054        }
055        
056        
057            /**
058             * find occurence of a pattern in a string (same like indexOf), but dont return first ocurence , it return
059             * struct with all information
060             * @param strPattern
061             * @param strInput
062             * @param offset
063             * @param caseSensitive
064             * @return
065             * @throws MalformedPatternException
066             */
067            public static Struct find(String strPattern, String strInput, int offset, boolean caseSensitive) throws MalformedPatternException {
068            
069            Perl5Matcher matcher = new Perl5Matcher();
070            PatternMatcherInput input = new PatternMatcherInput(strInput);
071            
072            
073            int compileOptions=caseSensitive ? 0 : Perl5Compiler.CASE_INSENSITIVE_MASK;
074            compileOptions+=Perl5Compiler.SINGLELINE_MASK;
075            if(offset < 1) offset = 1;
076            
077            
078            Pattern pattern = getPattern(strPattern,compileOptions);
079            
080      
081            if(offset <= strInput.length()) input.setCurrentOffset(offset - 1);
082            
083            if(offset <= strInput.length() && matcher.contains(input, pattern)) {
084                MatchResult result = matcher.getMatch();
085                
086                int groupCount = result.groups();
087                Array posArray = new ArrayImpl();
088                Array lenArray = new ArrayImpl();
089                for(int i = 0; i < groupCount; i++) {
090                    int off = result.beginOffset(i);
091                    posArray.appendEL(Integer.valueOf(off + 1));
092                    lenArray.appendEL(Integer.valueOf(result.endOffset(i) - off));
093                }
094                Struct struct = new StructImpl();
095                struct.setEL("pos", posArray);
096                struct.setEL("len", lenArray);
097                return struct;
098                
099            }
100            Array posArray = new ArrayImpl();
101            Array lenArray = new ArrayImpl();
102            posArray.appendEL(Constants.INTEGER_0);
103            lenArray.appendEL(Constants.INTEGER_0);
104            
105            Struct struct = new StructImpl();
106            struct.setEL("pos", posArray);
107            struct.setEL("len", lenArray);
108            return struct;
109        }
110            
111    
112            public static Array match(String strPattern, String strInput, int offset, boolean caseSensitive) throws MalformedPatternException {
113            
114            Perl5Matcher matcher = new Perl5Matcher();
115            PatternMatcherInput input = new PatternMatcherInput(strInput);
116            
117            
118            int compileOptions=caseSensitive ? 0 : Perl5Compiler.CASE_INSENSITIVE_MASK;
119            compileOptions+=Perl5Compiler.MULTILINE_MASK;
120            if(offset < 1) offset = 1;
121            
122            
123            Pattern pattern = getPattern(strPattern,compileOptions);
124            
125            
126            Array rtn = new ArrayImpl();
127            MatchResult result;
128            while(matcher.contains(input, pattern)) {
129              result = matcher.getMatch();  
130              rtn.appendEL(result.toString());
131              /*
132              System.out.println("Match: " + result.toString());
133              System.out.println("Length: " + result.length());
134              groups = result.groups();
135              System.out.println("Groups: " + groups);
136              System.out.println("Begin offset: " + result.beginOffset(0));
137              System.out.println("End offset: " + result.endOffset(0));
138              System.out.println("Saved Groups: ");
139    
140              // Start at 1 because we just printed out group 0
141              for(int group = 1; group < groups; group++) {
142                      System.out.println(group + ": " + result.group(group));
143                      System.out.println("Begin: " + result.begin(group));
144                      System.out.println("End: " + result.end(group));
145              }*/
146            }
147            return rtn;
148        }
149            
150            
151            private static Pattern getPattern(String strPattern, int type) throws MalformedPatternException {
152                Object o=patterns.get(strPattern+type);
153                if(o==null) {
154                    Pattern pattern = new Perl5Compiler().compile(strPattern, type);
155                    patterns.put(strPattern+type,pattern);
156                    return pattern;
157                }
158                return (Pattern) o;
159                
160            }
161            
162            /**
163             * replace the first/all occurence of given pattern
164             * @param strInput text to search pattern
165             * @param strPattern pattern to search
166             * @param replacement text to replace with pattern
167             * @param caseSensitive
168             * @param replaceAll do replace all or only one
169             * @return transformed text
170             * @throws MalformedPatternException
171             */
172            public static String replace(String strInput, String strPattern, String replacement, boolean caseSensitive, boolean replaceAll) throws MalformedPatternException {
173                return _replace(strInput,strPattern,escape(replacement),caseSensitive,replaceAll);
174            }
175            private static String _replace(String strInput, String strPattern, String replacement, boolean caseSensitive, boolean replaceAll) throws MalformedPatternException {
176                    Pattern pattern = getPattern(strPattern, caseSensitive?16:17);
177                    return Util.substitute(new Perl5Matcher(), pattern, new Perl5Substitution(replacement), strInput, replaceAll ? -1 : 1);
178            }
179            
180    
181            private static String escape(String replacement) throws MalformedPatternException {
182                replacement = _replace(replacement, "\\\\", "\\\\\\\\", false, true);
183                replacement=_escape(replacement);
184                replacement = _replace(replacement, "\\\\\\\\(\\d)", "\\$$1", false, true);
185                    return replacement;
186            }
187        private static String _escape(String str) {
188            StringBuffer sb=new StringBuffer();
189            int len=str.length();
190            char c;
191            
192            for(int i=0;i<len;i++) {
193                c=str.charAt(i);
194                
195                if('+'==c)                  sb.append("\\+");
196                else if('?'==c)             sb.append("\\?");
197                else if('$'==c)             sb.append("\\$");
198                else if('^'==c)             sb.append("\\^");
199                else if('\\'==c)    {
200                    if(i+1<len) {
201                        char n=str.charAt(i+1);
202                        if('\\'==n) {
203                            if(i+2<len) {
204                                char nn=str.charAt(i+2);
205                                    char x=0;
206                                    if('U'==nn)      x='U';
207                                    else if('L'==nn) x='L';
208                                    else if('u'==nn) x='u';
209                                    else if('l'==nn) x='l';
210                                    else if('E'==nn) x='E';
211                                    //else if('d'==nn) x='d';
212                                    if(x!=0) {
213                                        sb.append("\\"+x);
214                                        i+=2;
215                                        continue;
216                                    }
217                            }
218                        }
219                    }
220                    sb.append(c);
221                }
222                else sb.append(c);
223            }
224            return sb.toString();
225        }
226        
227        public static void main(String[] args) throws MalformedPatternException {
228            find(
229                    "<function[^>]*>.*?</function>",
230                    "<function name=\"susi2\" some=\"1\">\n<argument name=\"susi\">\naaa</function>",
231                    1,false);
232        }
233    }