Home | History | Annotate | Download | only in text
      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      */
     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      */
     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      */
     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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    151     public boolean didReachLimit() {
    152         return reachedLimit;
    153     }
    154 
    155     // implement UCaseProps.ContextIterator
    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 
    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