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  * Copyright (C) 1996-2011, International Business Machines Corporation and    *
      6  * others. All Rights Reserved.                                                *
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.text;
     10 
     11 import com.ibm.icu.impl.UCaseProps;
     12 import com.ibm.icu.lang.UCharacter;
     13 import com.ibm.icu.util.ULocale;
     14 
     15 /**
     16  * A transliterator that performs locale-sensitive toLower()
     17  * case mapping.
     18  */
     19 class LowercaseTransliterator extends Transliterator{
     20 
     21     /**
     22      * Package accessible ID.
     23      */
     24     static final String _ID = "Any-Lower";
     25 
     26     // TODO: Add variants for tr/az, lt, default = default locale: ICU ticket #12720
     27 
     28     /**
     29      * System registration hook.
     30      */
     31     static void register() {
     32         Transliterator.registerFactory(_ID, new Transliterator.Factory() {
     33             @Override
     34             public Transliterator getInstance(String ID) {
     35                 return new LowercaseTransliterator(ULocale.US);
     36             }
     37         });
     38 
     39         Transliterator.registerSpecialInverse("Lower", "Upper", true);
     40     }
     41 
     42     private final ULocale locale;
     43 
     44     private final UCaseProps csp;
     45     private ReplaceableContextIterator iter;
     46     private StringBuilder result;
     47     private int caseLocale;
     48 
     49     /**
     50      * Constructs a transliterator.
     51      */
     52 
     53     public LowercaseTransliterator(ULocale loc) {
     54         super(_ID, null);
     55         locale = loc;
     56         csp=UCaseProps.INSTANCE;
     57         iter=new ReplaceableContextIterator();
     58         result = new StringBuilder();
     59         caseLocale = UCaseProps.getCaseLocale(locale);
     60     }
     61 
     62     /**
     63      * Implements {@link Transliterator#handleTransliterate}.
     64      */
     65     @Override
     66     protected synchronized void handleTransliterate(Replaceable text,
     67                                        Position offsets, boolean isIncremental) {
     68         if(csp==null) {
     69             return;
     70         }
     71 
     72         if(offsets.start >= offsets.limit) {
     73             return;
     74         }
     75 
     76         iter.setText(text);
     77         result.setLength(0);
     78         int c, delta;
     79 
     80         // Walk through original string
     81         // If there is a case change, modify corresponding position in replaceable
     82 
     83         iter.setIndex(offsets.start);
     84         iter.setLimit(offsets.limit);
     85         iter.setContextLimits(offsets.contextStart, offsets.contextLimit);
     86         while((c=iter.nextCaseMapCP())>=0) {
     87             c=csp.toFullLower(c, iter, result, caseLocale);
     88 
     89             if(iter.didReachLimit() && isIncremental) {
     90                 // the case mapping function tried to look beyond the context limit
     91                 // wait for more input
     92                 offsets.start=iter.getCaseMapCPStart();
     93                 return;
     94             }
     95 
     96             /* decode the result */
     97             if(c<0) {
     98                 /* c mapped to itself, no change */
     99                 continue;
    100             } else if(c<=UCaseProps.MAX_STRING_LENGTH) {
    101                 /* replace by the mapping string */
    102                 delta=iter.replace(result.toString());
    103                 result.setLength(0);
    104             } else {
    105                 /* replace by single-code point mapping */
    106                 delta=iter.replace(UTF16.valueOf(c));
    107             }
    108 
    109             if(delta!=0) {
    110                 offsets.limit += delta;
    111                 offsets.contextLimit += delta;
    112             }
    113         }
    114         offsets.start = offsets.limit;
    115     }
    116 
    117     // NOTE: normally this would be static, but because the results vary by locale....
    118     SourceTargetUtility sourceTargetUtility = null;
    119 
    120     /* (non-Javadoc)
    121      * @see com.ibm.icu.text.Transliterator#addSourceTargetSet(com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet)
    122      */
    123     @Override
    124     public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) {
    125         synchronized (this) {
    126             if (sourceTargetUtility == null) {
    127                 sourceTargetUtility = new SourceTargetUtility(new Transform<String,String>() {
    128                     @Override
    129                     public String transform(String source) {
    130                         return UCharacter.toLowerCase(locale, source);
    131                     }
    132                 });
    133             }
    134         }
    135         sourceTargetUtility.addSourceTargetSet(this, inputFilter, sourceSet, targetSet);
    136     }
    137 }
    138