001: /*
002: *******************************************************************************
003: *
004: * Copyright (C) 2004-2005, International Business Machines
005: * Corporation and others. All Rights Reserved.
006: *
007: *******************************************************************************
008: * file name: ReplaceableContextIterator.java
009: * encoding: US-ASCII
010: * tab size: 8 (not used)
011: * indentation:4
012: *
013: * created on: 2005feb04
014: * created by: Markus W. Scherer
015: *
016: * Implementation of UCaseProps.ContextIterator, iterates over a Replaceable.
017: * Java port of casetrn.cpp/utrans_rep_caseContextIterator().
018: */
019:
020: package com.ibm.icu.text;
021:
022: import com.ibm.icu.impl.UCaseProps;
023: import com.ibm.icu.impl.UCharacterProperty;
024:
025: import com.ibm.icu.util.ULocale;
026:
027: /**
028: * Implementation of UCaseProps.ContextIterator, iterates over a Replaceable.
029: * See casetrn.cpp/utrans_rep_caseContextIterator().
030: * See also UCharacter.StringContextIterator.
031: * @internal
032: */
033: class ReplaceableContextIterator implements UCaseProps.ContextIterator {
034: /**
035: * Constructor.
036: * @param rep Replaceable to iterate over.
037: */
038: ReplaceableContextIterator() {
039: this .rep = null;
040: limit = cpStart = cpLimit = index = contextStart = contextLimit = 0;
041: dir = 0;
042: reachedLimit = false;
043: }
044:
045: /**
046: * Set the text for iteration.
047: * @param rep Iteration text.
048: */
049: public void setText(Replaceable rep) {
050: this .rep = rep;
051: limit = contextLimit = rep.length();
052: cpStart = cpLimit = index = contextStart = 0;
053: dir = 0;
054: reachedLimit = false;
055: }
056:
057: /**
058: * Set the index where nextCaseMapCP() is to start iterating.
059: * @param index Iteration start index for nextCaseMapCP().
060: */
061: public void setIndex(int index) {
062: cpStart = cpLimit = index;
063: this .index = 0;
064: dir = 0;
065: reachedLimit = false;
066: }
067:
068: /**
069: * Get the index of where the code point currently being case-mapped starts.
070: * @return The start index of the current code point.
071: */
072: public int getCaseMapCPStart() {
073: return cpStart;
074: }
075:
076: /**
077: * Set the iteration limit for nextCaseMapCP() to an index within the string.
078: * If the limit parameter is negative or past the string, then the
079: * string length is restored as the iteration limit.
080: *
081: * @param lim The iteration limit.
082: */
083: public void setLimit(int lim) {
084: if (0 <= lim && lim <= rep.length()) {
085: limit = lim;
086: } else {
087: limit = rep.length();
088: }
089: reachedLimit = false;
090: }
091:
092: /**
093: * Set the start and limit indexes for context iteration with next().
094: * @param contextStart Start of context for next().
095: * @param contextLimit Limit of context for next().
096: */
097: public void setContextLimits(int contextStart, int contextLimit) {
098: if (contextStart < 0) {
099: this .contextStart = 0;
100: } else if (contextStart <= rep.length()) {
101: this .contextStart = contextStart;
102: } else {
103: this .contextStart = rep.length();
104: }
105: if (contextLimit < this .contextStart) {
106: this .contextLimit = this .contextStart;
107: } else if (contextLimit <= rep.length()) {
108: this .contextLimit = contextLimit;
109: } else {
110: this .contextLimit = rep.length();
111: }
112: reachedLimit = false;
113: }
114:
115: /**
116: * Iterate forward through the string to fetch the next code point
117: * to be case-mapped, and set the context indexes for it.
118: *
119: * @return The next code point to be case-mapped, or <0 when the iteration is done.
120: */
121: public int nextCaseMapCP() {
122: int c;
123: if (cpLimit < limit) {
124: cpStart = cpLimit;
125: c = rep.char32At(cpLimit);
126: cpLimit += UTF16.getCharCount(c);
127: return c;
128: } else {
129: return -1;
130: }
131: }
132:
133: /**
134: * Replace the current code point by its case mapping,
135: * and update the indexes.
136: *
137: * @param text Replacement text.
138: * @return The delta for the change of the text length.
139: */
140: public int replace(String text) {
141: int delta = text.length() - (cpLimit - cpStart);
142: rep.replace(cpStart, cpLimit, text);
143: cpLimit += delta;
144: limit += delta;
145: contextLimit += delta;
146: return delta;
147: }
148:
149: /**
150: * Did forward context iteration with next() reach the iteration limit?
151: * @return Boolean value.
152: */
153: public boolean didReachLimit() {
154: return reachedLimit;
155: }
156:
157: // implement UCaseProps.ContextIterator
158: public void reset(int dir) {
159: if (dir > 0) {
160: /* reset for forward iteration */
161: this .dir = 1;
162: index = cpLimit;
163: } else if (dir < 0) {
164: /* reset for backward iteration */
165: this .dir = -1;
166: index = cpStart;
167: } else {
168: // not a valid direction
169: this .dir = 0;
170: index = 0;
171: }
172: reachedLimit = false;
173: }
174:
175: public int next() {
176: int c;
177:
178: if (dir > 0) {
179: if (index < contextLimit) {
180: c = rep.char32At(index);
181: index += UTF16.getCharCount(c);
182: return c;
183: } else {
184: // forward context iteration reached the limit
185: reachedLimit = true;
186: }
187: } else if (dir < 0 && index > contextStart) {
188: c = rep.char32At(index - 1);
189: index -= UTF16.getCharCount(c);
190: return c;
191: }
192: return -1;
193: }
194:
195: // variables
196: protected Replaceable rep;
197: protected int index, limit, cpStart, cpLimit, contextStart,
198: contextLimit;
199: protected int dir; // 0=initial state >0=forward <0=backward
200: protected boolean reachedLimit;
201: }
|