001: /**
002: * Copyright (c) 2001, Sergey A. Samokhodkin
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without modification,
006: * are permitted provided that the following conditions are met:
007: *
008: * - Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * - Redistributions in binary form
011: * must reproduce the above copyright notice, this list of conditions and the following
012: * disclaimer in the documentation and/or other materials provided with the distribution.
013: * - Neither the name of jregex nor the names of its contributors may be used
014: * to endorse or promote products derived from this software without specific prior
015: * written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
018: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: * IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
021: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
022: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
023: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
024: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
025: * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
026: *
027: * @version 1.2_01
028: */package jregex;
029:
030: import java.io.*;
031: import java.util.Hashtable;
032:
033: /**
034: * <b>The Replacer class</b> suggests some methods to replace occurences of a pattern
035: * either by a result of evaluation of a perl-like expression, or by a plain string,
036: * or according to a custom substitution model, provided as a Substitution interface implementation.<br>
037: * A Replacer instance may be obtained either using Pattern.replacer(...) method, or by constructor:<pre>
038: * Pattern p=new Pattern("\\w+");
039: * Replacer perlExpressionReplacer=p.replacer("[$&]");
040: * //or another way to do the same
041: * Substitution myOwnModel=new Substitution(){
042: * public void appendSubstitution(MatchResult match,TextBuffer tb){
043: * tb.append('[');
044: * match.getGroup(MatchResult.MATCH,tb);
045: * tb.append(']');
046: * }
047: * }
048: * Replacer myVeryOwnReplacer=new Replacer(p,myOwnModel);
049: * </pre>
050: * The second method is much more verbose, but gives more freedom.
051: * To perform a replacement call replace(someInput):<pre>
052: * System.out.print(perlExpressionReplacer.replace("All your base "));
053: * System.out.println(myVeryOwnReplacer.replace("are belong to us"));
054: * //result: "[All] [your] [base] [are] [belong] [to] [us]"
055: * </pre>
056: * @see Substitution
057: * @see PerlSubstitution
058: * @see Replacer#Replacer(jregex.Pattern,jregex.Substitution)
059: */
060:
061: public class Replacer {
062: private Pattern pattern;
063: private Substitution substitution;
064:
065: /**
066: */
067: public Replacer(Pattern pattern, Substitution substitution) {
068: this .pattern = pattern;
069: this .substitution = substitution;
070: }
071:
072: /**
073: */
074: public Replacer(Pattern pattern, String substitution) {
075: this (pattern, substitution, true);
076: }
077:
078: /**
079: */
080: public Replacer(Pattern pattern, String substitution,
081: boolean isPerlExpr) {
082: this .pattern = pattern;
083: this .substitution = isPerlExpr ? (Substitution) new PerlSubstitution(
084: substitution)
085: : new DummySubstitution(substitution);
086: }
087:
088: public void setSubstitution(String s, boolean isPerlExpr) {
089: substitution = isPerlExpr ? (Substitution) new PerlSubstitution(
090: s)
091: : new DummySubstitution(s);
092: }
093:
094: /**
095: */
096: public String replace(String text) {
097: TextBuffer tb = wrap(new StringBuffer(text.length()));
098: replace(pattern.matcher(text), substitution, tb);
099: return tb.toString();
100: }
101:
102: /**
103: */
104: public String replace(char[] chars, int off, int len) {
105: TextBuffer tb = wrap(new StringBuffer(len));
106: replace(pattern.matcher(chars, off, len), substitution, tb);
107: return tb.toString();
108: }
109:
110: /**
111: */
112: public String replace(MatchResult res, int group) {
113: TextBuffer tb = wrap(new StringBuffer());
114: replace(pattern.matcher(res, group), substitution, tb);
115: return tb.toString();
116: }
117:
118: /**
119: */
120: public String replace(Reader text, int length) throws IOException {
121: TextBuffer tb = wrap(new StringBuffer(length >= 0 ? length : 0));
122: replace(pattern.matcher(text, length), substitution, tb);
123: return tb.toString();
124: }
125:
126: /**
127: */
128: public int replace(String text, StringBuffer sb) {
129: return replace(pattern.matcher(text), substitution, wrap(sb));
130: }
131:
132: /**
133: */
134: public int replace(char[] chars, int off, int len, StringBuffer sb) {
135: return replace(chars, off, len, wrap(sb));
136: }
137:
138: /**
139: */
140: public int replace(MatchResult res, int group, StringBuffer sb) {
141: return replace(res, group, wrap(sb));
142: }
143:
144: /**
145: */
146: public int replace(MatchResult res, String groupName,
147: StringBuffer sb) {
148: return replace(res, groupName, wrap(sb));
149: }
150:
151: public int replace(Reader text, int length, StringBuffer sb)
152: throws IOException {
153: return replace(text, length, wrap(sb));
154: }
155:
156: /**
157: */
158: public int replace(String text, TextBuffer dest) {
159: return replace(pattern.matcher(text), substitution, dest);
160: }
161:
162: /**
163: */
164: public int replace(char[] chars, int off, int len, TextBuffer dest) {
165: return replace(pattern.matcher(chars, off, len), substitution,
166: dest);
167: }
168:
169: /**
170: */
171: public int replace(MatchResult res, int group, TextBuffer dest) {
172: return replace(pattern.matcher(res, group), substitution, dest);
173: }
174:
175: /**
176: */
177: public int replace(MatchResult res, String groupName,
178: TextBuffer dest) {
179: return replace(pattern.matcher(res, groupName), substitution,
180: dest);
181: }
182:
183: public int replace(Reader text, int length, TextBuffer dest)
184: throws IOException {
185: return replace(pattern.matcher(text, length), substitution,
186: dest);
187: }
188:
189: /**
190: * Replaces all occurences of a matcher's pattern in a matcher's target
191: * by a given substitution appending the result to a buffer.<br>
192: * The substitution starts from current matcher's position, current match
193: * not included.
194: */
195: public static int replace(Matcher m, Substitution substitution,
196: TextBuffer dest) {
197: boolean firstPass = true;
198: int c = 0;
199: while (m.find()) {
200: if (m.end() == 0 && !firstPass)
201: continue; //allow to replace at "^"
202: if (m.start() > 0)
203: m.getGroup(MatchResult.PREFIX, dest);
204: substitution.appendSubstitution(m, dest);
205: c++;
206: m.setTarget(m, MatchResult.SUFFIX);
207: firstPass = false;
208: }
209: m.getGroup(MatchResult.TARGET, dest);
210: return c;
211: }
212:
213: public static int replace(Matcher m, Substitution substitution,
214: Writer out) throws IOException {
215: try {
216: return replace(m, substitution, wrap(out));
217: } catch (WriteException e) {
218: throw e.reason;
219: }
220: }
221:
222: /**
223: */
224: public void replace(String text, Writer out) throws IOException {
225: replace(pattern.matcher(text), substitution, out);
226: }
227:
228: /**
229: */
230: public void replace(char[] chars, int off, int len, Writer out)
231: throws IOException {
232: replace(pattern.matcher(chars, off, len), substitution, out);
233: }
234:
235: /**
236: */
237: public void replace(MatchResult res, int group, Writer out)
238: throws IOException {
239: replace(pattern.matcher(res, group), substitution, out);
240: }
241:
242: /**
243: */
244: public void replace(MatchResult res, String groupName, Writer out)
245: throws IOException {
246: replace(pattern.matcher(res, groupName), substitution, out);
247: }
248:
249: public void replace(Reader in, int length, Writer out)
250: throws IOException {
251: replace(pattern.matcher(in, length), substitution, out);
252: }
253:
254: private static class DummySubstitution implements Substitution {
255: String str;
256:
257: DummySubstitution(String s) {
258: str = s;
259: }
260:
261: public void appendSubstitution(MatchResult match, TextBuffer res) {
262: if (str != null)
263: res.append(str);
264: }
265: }
266:
267: public static TextBuffer wrap(final StringBuffer sb) {
268: return new TextBuffer() {
269: public void append(char c) {
270: sb.append(c);
271: }
272:
273: public void append(char[] chars, int start, int len) {
274: sb.append(chars, start, len);
275: }
276:
277: public void append(String s) {
278: sb.append(s);
279: }
280:
281: public String toString() {
282: return sb.toString();
283: }
284: };
285: }
286:
287: public static TextBuffer wrap(final Writer writer) {
288: return new TextBuffer() {
289: public void append(char c) {
290: try {
291: writer.write(c);
292: } catch (IOException e) {
293: throw new WriteException(e);
294: }
295: }
296:
297: public void append(char[] chars, int off, int len) {
298: try {
299: writer.write(chars, off, len);
300: } catch (IOException e) {
301: throw new WriteException(e);
302: }
303: }
304:
305: public void append(String s) {
306: try {
307: writer.write(s);
308: } catch (IOException e) {
309: throw new WriteException(e);
310: }
311: }
312: };
313: }
314:
315: private static class WriteException extends RuntimeException {
316: IOException reason;
317:
318: WriteException(IOException io) {
319: reason = io;
320: }
321: }
322: }
|