]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/translit/src/com/ibm/icu/text/NameUnicodeTransliterator.java
Upgrade ICU4J.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / translit / src / com / ibm / icu / text / NameUnicodeTransliterator.java
1 /*
2  * Copyright (C) 1996-2011, International Business Machines Corporation and
3  * others. All Rights Reserved.
4  */
5 package com.ibm.icu.text;
6 import com.ibm.icu.impl.PatternProps;
7 import com.ibm.icu.impl.UCharacterName;
8 import com.ibm.icu.impl.Utility;
9 import com.ibm.icu.lang.UCharacter;
10
11 /**
12  * A transliterator that performs name to character mapping.
13  * @author Alan Liu
14  */
15 class NameUnicodeTransliterator extends Transliterator {
16
17     static final String _ID = "Name-Any";
18
19     static final String OPEN_PAT    = "\\N~{~";
20     static final char   OPEN_DELIM  = '\\'; // first char of OPEN_PAT
21     static final char   CLOSE_DELIM = '}';
22     static final char   SPACE       = ' ';
23
24
25     /**
26      * System registration hook.
27      */
28     static void register() {
29         Transliterator.registerFactory(_ID, new Transliterator.Factory() {
30             public Transliterator getInstance(String ID) {
31                 return new NameUnicodeTransliterator(null);
32             }
33         });
34     }
35
36     /**
37      * Constructs a transliterator.
38      */
39     public NameUnicodeTransliterator(UnicodeFilter filter) {
40         super(_ID, filter);
41     }
42
43     /**
44      * Implements {@link Transliterator#handleTransliterate}.
45      */
46     protected void handleTransliterate(Replaceable text,
47                                        Position offsets, boolean isIncremental) {
48
49         int maxLen = UCharacterName.INSTANCE.getMaxCharNameLength() + 1; // allow for temporary trailing space
50
51         StringBuffer name = new StringBuffer(maxLen);
52
53         // Get the legal character set
54         UnicodeSet legal = new UnicodeSet();
55         UCharacterName.INSTANCE.getCharNameCharacters(legal);
56
57         int cursor = offsets.start;
58         int limit = offsets.limit;
59
60         // Modes:
61         // 0 - looking for open delimiter
62         // 1 - after open delimiter
63         int mode = 0;
64         int openPos = -1; // open delim candidate pos
65         
66         int c;
67         while (cursor < limit) {
68             c = text.char32At(cursor);
69
70             switch (mode) {
71             case 0: // looking for open delimiter
72                 if (c == OPEN_DELIM) { // quick check first
73                     openPos = cursor;
74                     int i = Utility.parsePattern(OPEN_PAT, text, cursor, limit);
75                     if (i >= 0 && i < limit) {
76                         mode = 1;
77                         name.setLength(0);
78                         cursor = i;
79                         continue; // *** reprocess char32At(cursor)
80                     }
81                 }
82                 break;
83
84             case 1: // after open delimiter
85                 // Look for legal chars.  If \s+ is found, convert it
86                 // to a single space.  If closeDelimiter is found, exit
87                 // the loop.  If any other character is found, exit the
88                 // loop.  If the limit is reached, exit the loop.
89                 
90                 // Convert \s+ => SPACE.  This assumes there are no
91                 // runs of >1 space characters in names.
92                 if (PatternProps.isWhiteSpace(c)) {
93                     // Ignore leading whitespace
94                     if (name.length() > 0 &&
95                         name.charAt(name.length()-1) != SPACE) {
96                         name.append(SPACE);
97                         // If we are too long then abort.  maxLen includes
98                         // temporary trailing space, so use '>'.
99                         if (name.length() > maxLen) {
100                             mode = 0;
101                         }
102                     }
103                     break;
104                 }
105
106                 if (c == CLOSE_DELIM) {
107
108                     int len = name.length();
109                     
110                     // Delete trailing space, if any
111                     if (len > 0 &&
112                         name.charAt(len-1) == SPACE) {
113                         name.setLength(--len);
114                     }
115
116                     c = UCharacter.getCharFromExtendedName(name.toString());
117                     if (c != -1) {
118                         // Lookup succeeded
119
120                         // assert(UTF16.getCharCount(CLOSE_DELIM) == 1);
121                         cursor++; // advance over CLOSE_DELIM
122
123                         String str = UTF16.valueOf(c);
124                         text.replace(openPos, cursor, str);
125
126                         // Adjust indices for the change in the length of
127                         // the string.  Do not assume that str.length() ==
128                         // 1, in case of surrogates.
129                         int delta = cursor - openPos - str.length();
130                         cursor -= delta;
131                         limit -= delta;
132                         // assert(cursor == openPos + str.length());
133                     }
134                     // If the lookup failed, we leave things as-is and
135                     // still switch to mode 0 and continue.
136                     mode = 0;
137                     openPos = -1; // close off candidate
138                     continue; // *** reprocess char32At(cursor)
139                 }
140
141                 if (legal.contains(c)) {
142                     UTF16.append(name, c);
143                     // If we go past the longest possible name then abort.
144                     // maxLen includes temporary trailing space, so use '>='.
145                     if (name.length() >= maxLen) {
146                         mode = 0;
147                     }
148                 }
149
150                 // Invalid character
151                 else {
152                     --cursor; // Backup and reprocess this character
153                     mode = 0;
154                 }
155
156                 break;
157             }
158
159             cursor += UTF16.getCharCount(c);
160         }
161
162         offsets.contextLimit += limit - offsets.limit;
163         offsets.limit = limit;
164         // In incremental mode, only advance the cursor up to the last
165         // open delimiter candidate.
166         offsets.start = (isIncremental && openPos >= 0) ? openPos : cursor;
167     }
168
169     /* (non-Javadoc)
170      * @see com.ibm.icu.text.Transliterator#addSourceTargetSet(com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet)
171      */
172     @Override
173     public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) {
174         UnicodeSet myFilter = getFilterAsUnicodeSet(inputFilter);
175         if (!myFilter.containsAll(UnicodeNameTransliterator.OPEN_DELIM) || !myFilter.contains(CLOSE_DELIM)) {
176             return; // we have to contain both prefix and suffix 
177         }
178         UnicodeSet items = new UnicodeSet()
179         .addAll('0', '9')
180         .addAll('A', 'F')
181         .addAll('a', 'z') // for controls
182         .add('<').add('>') // for controls
183         .add('(').add(')') // for controls
184         .add('-')
185         .add(' ')
186         .addAll(UnicodeNameTransliterator.OPEN_DELIM)
187         .add(CLOSE_DELIM);
188         items.retainAll(myFilter);
189         if (items.size() > 0) {
190             sourceSet.addAll(items);
191             // could produce any character
192             targetSet.addAll(0, 0x10FFFF);
193         }
194     }
195 }