1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * 6 * Copyright (C) 2004-2010, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 * 9 ******************************************************************************* 10 * file name: ReplaceableContextIterator.java 11 * encoding: US-ASCII 12 * tab size: 8 (not used) 13 * indentation:4 14 * 15 * created on: 2005feb04 16 * created by: Markus W. Scherer 17 * 18 * Implementation of UCaseProps.ContextIterator, iterates over a Replaceable. 19 * Java port of casetrn.cpp/utrans_rep_caseContextIterator(). 20 */ 21 22 package com.ibm.icu.text; 23 24 import com.ibm.icu.impl.UCaseProps; 25 26 /** 27 * Implementation of UCaseProps.ContextIterator, iterates over a Replaceable. 28 * See casetrn.cpp/utrans_rep_caseContextIterator(). 29 * See also UCharacter.StringContextIterator. 30 */ 31 class ReplaceableContextIterator implements UCaseProps.ContextIterator { 32 /** 33 * Constructor. 34 * @param rep Replaceable to iterate over. 35 */ ReplaceableContextIterator()36 ReplaceableContextIterator() { 37 this.rep=null; 38 limit=cpStart=cpLimit=index=contextStart=contextLimit=0; 39 dir=0; 40 reachedLimit=false; 41 } 42 43 /** 44 * Set the text for iteration. 45 * @param rep Iteration text. 46 */ setText(Replaceable rep)47 public void setText(Replaceable rep) { 48 this.rep=rep; 49 limit=contextLimit=rep.length(); 50 cpStart=cpLimit=index=contextStart=0; 51 dir=0; 52 reachedLimit=false; 53 } 54 55 /** 56 * Set the index where nextCaseMapCP() is to start iterating. 57 * @param index Iteration start index for nextCaseMapCP(). 58 */ setIndex(int index)59 public void setIndex(int index) { 60 cpStart=cpLimit=index; 61 this.index=0; 62 dir=0; 63 reachedLimit=false; 64 } 65 66 /** 67 * Get the index of where the code point currently being case-mapped starts. 68 * @return The start index of the current code point. 69 */ getCaseMapCPStart()70 public int getCaseMapCPStart() { 71 return cpStart; 72 } 73 74 /** 75 * Set the iteration limit for nextCaseMapCP() to an index within the string. 76 * If the limit parameter is negative or past the string, then the 77 * string length is restored as the iteration limit. 78 * 79 * @param lim The iteration limit. 80 */ setLimit(int lim)81 public void setLimit(int lim) { 82 if(0<=lim && lim<=rep.length()) { 83 limit=lim; 84 } else { 85 limit=rep.length(); 86 } 87 reachedLimit=false; 88 } 89 90 /** 91 * Set the start and limit indexes for context iteration with next(). 92 * @param contextStart Start of context for next(). 93 * @param contextLimit Limit of context for next(). 94 */ setContextLimits(int contextStart, int contextLimit)95 public void setContextLimits(int contextStart, int contextLimit) { 96 if(contextStart<0) { 97 this.contextStart=0; 98 } else if(contextStart<=rep.length()) { 99 this.contextStart=contextStart; 100 } else { 101 this.contextStart=rep.length(); 102 } 103 if(contextLimit<this.contextStart) { 104 this.contextLimit=this.contextStart; 105 } else if(contextLimit<=rep.length()) { 106 this.contextLimit=contextLimit; 107 } else { 108 this.contextLimit=rep.length(); 109 } 110 reachedLimit=false; 111 } 112 113 /** 114 * Iterate forward through the string to fetch the next code point 115 * to be case-mapped, and set the context indexes for it. 116 * 117 * @return The next code point to be case-mapped, or <0 when the iteration is done. 118 */ nextCaseMapCP()119 public int nextCaseMapCP() { 120 int c; 121 if(cpLimit<limit) { 122 cpStart=cpLimit; 123 c=rep.char32At(cpLimit); 124 cpLimit+=UTF16.getCharCount(c); 125 return c; 126 } else { 127 return -1; 128 } 129 } 130 131 /** 132 * Replace the current code point by its case mapping, 133 * and update the indexes. 134 * 135 * @param text Replacement text. 136 * @return The delta for the change of the text length. 137 */ replace(String text)138 public int replace(String text) { 139 int delta=text.length()-(cpLimit-cpStart); 140 rep.replace(cpStart, cpLimit, text); 141 cpLimit+=delta; 142 limit+=delta; 143 contextLimit+=delta; 144 return delta; 145 } 146 147 /** 148 * Did forward context iteration with next() reach the iteration limit? 149 * @return Boolean value. 150 */ didReachLimit()151 public boolean didReachLimit() { 152 return reachedLimit; 153 } 154 155 // implement UCaseProps.ContextIterator reset(int direction)156 public void reset(int direction) { 157 if(direction>0) { 158 /* reset for forward iteration */ 159 this.dir=1; 160 index=cpLimit; 161 } else if(direction<0) { 162 /* reset for backward iteration */ 163 this.dir=-1; 164 index=cpStart; 165 } else { 166 // not a valid direction 167 this.dir=0; 168 index=0; 169 } 170 reachedLimit=false; 171 } 172 next()173 public int next() { 174 int c; 175 176 if(dir>0) { 177 if(index<contextLimit) { 178 c=rep.char32At(index); 179 index+=UTF16.getCharCount(c); 180 return c; 181 } else { 182 // forward context iteration reached the limit 183 reachedLimit=true; 184 } 185 } else if(dir<0 && index>contextStart) { 186 c=rep.char32At(index-1); 187 index-=UTF16.getCharCount(c); 188 return c; 189 } 190 return -1; 191 } 192 193 // variables 194 protected Replaceable rep; 195 protected int index, limit, cpStart, cpLimit, contextStart, contextLimit; 196 protected int dir; // 0=initial state >0=forward <0=backward 197 protected boolean reachedLimit; 198 } 199