| /* |
| * Copyright (C) 1996-2000, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| * |
| * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/text/Attic/TransformTransliterator.java,v $ |
| * $Date: 2001/09/28 20:27:02 $ |
| * $Revision: 1.2 $ |
| */ |
| package com.ibm.text; |
| import java.util.*; |
| |
| /** |
| * An abstract class for transliterators based on a transform |
| * operation. To create a transliterator that implements a |
| * transformation, create a subclass of this class and implement the |
| * abstract <code>transform()</code> and <code>hasTransform()</code> |
| * methods. |
| * @author Alan Liu |
| */ |
| public abstract class TransformTransliterator extends Transliterator { |
| |
| /** |
| * Constructs a transliterator. For use by subclasses. |
| */ |
| protected TransformTransliterator(String id, UnicodeFilter f) { |
| super(id, f); |
| } |
| |
| /** |
| * Implements {@link Transliterator#handleTransliterate}. |
| */ |
| protected void handleTransliterate(Replaceable text, |
| Position offsets, boolean incremental) { |
| |
| int start; |
| for (start = offsets.start; start < offsets.limit; ++start) { |
| // Scan for the first character that is != its transform. |
| // If there are none, we fall out without doing anything. |
| char c = text.charAt(start); |
| if (hasTransform(c)) { |
| // There is a transforming character at start. Break |
| // up the remaining string, from start to |
| // offsets.limit, into segments of unfiltered and |
| // filtered characters. Only transform the unfiltered |
| // characters. As always, minimize the number of |
| // calls to Replaceable.replace(). |
| |
| int len = offsets.limit - start; |
| // assert(len >= 1); |
| |
| char[] buf = new char[len]; |
| text.getChars(start, offsets.limit, buf, 0); |
| |
| int segStart = 0; |
| int segLimit; |
| UnicodeFilter filt = getFilter(); |
| |
| // lenDelta is the accumulated length difference for |
| // all transformed segments. It is new length - old |
| // length. |
| int lenDelta = 0; |
| |
| // Set segStart, segLimit to the unfiltered segment |
| // starting with start. If the filter is null, then |
| // segStart/Limit will be set to the whole string, |
| // that is, 0/len. |
| do { |
| // Set segLimit to the first filtered char at or |
| // after segStart. |
| segLimit = len; |
| if (filt != null) { |
| segLimit = segStart; |
| while (segLimit < len && filt.contains(buf[segLimit])) { |
| ++segLimit; |
| } |
| } |
| |
| // Transform the unfiltered chars between segStart |
| // and segLimit. |
| int segLen = segLimit - segStart; |
| if (segLen != 0) { |
| String newStr = transform( |
| new String(buf, segStart, segLen)); |
| text.replace(start, start + segLen, newStr); |
| start += newStr.length(); |
| lenDelta += newStr.length() - segLen; |
| } |
| |
| // Set segStart to the first unfiltered char at or |
| // after segLimit. |
| segStart = segLimit; |
| if (filt != null) { |
| while (segStart < len && !filt.contains(buf[segStart])) { |
| ++segStart; |
| } |
| } |
| start += segStart - segLimit; |
| |
| } while (segStart < len); |
| |
| offsets.limit += lenDelta; |
| offsets.contextLimit += lenDelta; |
| offsets.start = offsets.limit; |
| return; |
| } |
| } |
| // assert(start == offsets.limit); |
| offsets.start = start; |
| } |
| |
| /** |
| * Subclasses must implement this method to determine whether a |
| * given character has a transform that is not equal to itself. |
| * This is approximately equivalent to <code>c != |
| * transform(String.valueOf(c))</code>, where |
| * <code>String.valueOf(c)</code> returns a String containing the |
| * single character (not integer) <code>c</code>. Subclasses that |
| * transform all their input can simply return <code>true</code>. |
| */ |
| protected abstract boolean hasTransform(int c); |
| |
| /** |
| * Subclasses must implement this method to transform a string. |
| */ |
| protected abstract String transform(String s); |
| } |