• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2016 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 /*
5  * Copyright (C) 1996-2011, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  *
8  */
9 package ohos.global.icu.text;
10 
11 import ohos.global.icu.impl.UCaseProps;
12 import ohos.global.icu.lang.UCharacter;
13 import ohos.global.icu.util.ULocale;
14 
15 /**
16  * A transliterator that converts all letters (as defined by
17  * <code>UCharacter.isLetter()</code>) to lower case, except for those
18  * letters preceded by non-letters.  The latter are converted to title
19  * case using <code>UCharacter.toTitleCase()</code>.
20  * @author Alan Liu
21  */
22 class TitlecaseTransliterator extends Transliterator {
23 
24     static final String _ID = "Any-Title";
25     // TODO: Add variants for tr/az, lt, default = default locale: ICU ticket #12720
26 
27     /**
28      * System registration hook.
29      */
register()30     static void register() {
31         Transliterator.registerFactory(_ID, new Transliterator.Factory() {
32             @Override
33             public Transliterator getInstance(String ID) {
34                 return new TitlecaseTransliterator(ULocale.US);
35             }
36         });
37 
38         registerSpecialInverse("Title", "Lower", false);
39     }
40 
41     private final ULocale locale;
42 
43     private final UCaseProps csp;
44     private ReplaceableContextIterator iter;
45     private StringBuilder result;
46     private int caseLocale;
47 
48    /**
49      * Constructs a transliterator.
50      */
TitlecaseTransliterator(ULocale loc)51     public TitlecaseTransliterator(ULocale loc) {
52         super(_ID, null);
53         locale = loc;
54         // Need to look back 2 characters in the case of "can't"
55         setMaximumContextLength(2);
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
handleTransliterate(Replaceable text, Position offsets, boolean isIncremental)66     protected synchronized void handleTransliterate(Replaceable text,
67                                        Position offsets, boolean isIncremental) {
68         // TODO reimplement, see ustrcase.c
69         // using a real word break iterator
70         //   instead of just looking for a transition between cased and uncased characters
71         // call CaseMapTransliterator::handleTransliterate() for lowercasing? (set fMap)
72         // needs to take isIncremental into account because case mappings are context-sensitive
73         //   also detect when lowercasing function did not finish because of context
74 
75         if (offsets.start >= offsets.limit) {
76             return;
77         }
78 
79         // case type: >0 cased (UCaseProps.LOWER etc.)  ==0 uncased  <0 case-ignorable
80         int type;
81 
82         // Our mode; we are either converting letter toTitle or
83         // toLower.
84         boolean doTitle = true;
85 
86         // Determine if there is a preceding context of cased case-ignorable*,
87         // in which case we want to start in toLower mode.  If the
88         // prior context is anything else (including empty) then start
89         // in toTitle mode.
90         int c, start;
91         for (start = offsets.start - 1; start >= offsets.contextStart; start -= UTF16.getCharCount(c)) {
92             c = text.char32At(start);
93             type=csp.getTypeOrIgnorable(c);
94             if(type>0) { // cased
95                 doTitle=false;
96                 break;
97             } else if(type==0) { // uncased but not ignorable
98                 break;
99             }
100             // else (type<0) case-ignorable: continue
101         }
102 
103         // Convert things after a cased character toLower; things
104         // after a uncased, non-case-ignorable character toTitle.  Case-ignorable
105         // characters are copied directly and do not change the mode.
106 
107         iter.setText(text);
108         iter.setIndex(offsets.start);
109         iter.setLimit(offsets.limit);
110         iter.setContextLimits(offsets.contextStart, offsets.contextLimit);
111 
112         result.setLength(0);
113 
114         // Walk through original string
115         // If there is a case change, modify corresponding position in replaceable
116         int delta;
117 
118         while((c=iter.nextCaseMapCP())>=0) {
119             type=csp.getTypeOrIgnorable(c);
120             if(type>=0) { // not case-ignorable
121                 if(doTitle) {
122                     c=csp.toFullTitle(c, iter, result, caseLocale);
123                 } else {
124                     c=csp.toFullLower(c, iter, result, caseLocale);
125                 }
126                 doTitle = type==0; // doTitle=isUncased
127 
128                 if(iter.didReachLimit() && isIncremental) {
129                     // the case mapping function tried to look beyond the context limit
130                     // wait for more input
131                     offsets.start=iter.getCaseMapCPStart();
132                     return;
133                 }
134 
135                 /* decode the result */
136                 if(c<0) {
137                     /* c mapped to itself, no change */
138                     continue;
139                 } else if(c<=UCaseProps.MAX_STRING_LENGTH) {
140                     /* replace by the mapping string */
141                     delta=iter.replace(result.toString());
142                     result.setLength(0);
143                 } else {
144                     /* replace by single-code point mapping */
145                     delta=iter.replace(UTF16.valueOf(c));
146                 }
147 
148                 if(delta!=0) {
149                     offsets.limit += delta;
150                     offsets.contextLimit += delta;
151                 }
152             }
153         }
154         offsets.start = offsets.limit;
155     }
156 
157     // NOTE: normally this would be static, but because the results vary by locale....
158     SourceTargetUtility sourceTargetUtility = null;
159 
160     /* (non-Javadoc)
161      * @see ohos.global.icu.text.Transliterator#addSourceTargetSet(ohos.global.icu.text.UnicodeSet, ohos.global.icu.text.UnicodeSet, ohos.global.icu.text.UnicodeSet)
162      */
163     @Override
addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet)164     public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) {
165         synchronized (this) {
166             if (sourceTargetUtility == null) {
167                 sourceTargetUtility = new SourceTargetUtility(new Transform<String,String>() {
168                     @Override
169                     public String transform(String source) {
170                         return UCharacter.toTitleCase(locale, source, null);
171                     }
172                 });
173             }
174         }
175         sourceTargetUtility.addSourceTargetSet(this, inputFilter, sourceSet, targetSet);
176     }
177 }
178