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 }