BurmeseBreakEngine.java revision 2ae130017183d2f66d55bf0ca51f8da3294644fd
1/* GENERATED SOURCE. DO NOT MODIFY. */
2/*
3 *******************************************************************************
4 * Copyright (C) 2014, International Business Machines Corporation and         *
5 * others. All Rights Reserved.                                                *
6 *******************************************************************************
7 */
8package android.icu.text;
9
10import java.io.IOException;
11import java.text.CharacterIterator;
12
13import android.icu.lang.UCharacter;
14import android.icu.lang.UProperty;
15import android.icu.lang.UScript;
16
17class BurmeseBreakEngine extends DictionaryBreakEngine {
18
19    // Constants for BurmeseBreakIterator
20    // How many words in a row are "good enough"?
21    private static final byte BURMESE_LOOKAHEAD = 3;
22    // Will not combine a non-word with a preceding dictionary word longer than this
23    private static final byte BURMESE_ROOT_COMBINE_THRESHOLD = 3;
24    // Will not combine a non-word that shares at least this much prefix with a
25    // dictionary word with a preceding word
26    private static final byte BURMESE_PREFIX_COMBINE_THRESHOLD = 3;
27    // Minimum word size
28    private static final byte BURMESE_MIN_WORD = 2;
29
30    private DictionaryMatcher fDictionary;
31    private static UnicodeSet fBurmeseWordSet;
32    private static UnicodeSet fEndWordSet;
33    private static UnicodeSet fBeginWordSet;
34    private static UnicodeSet fMarkSet;
35
36    static {
37        // Initialize UnicodeSets
38        fBurmeseWordSet = new UnicodeSet();
39        fMarkSet = new UnicodeSet();
40        fBeginWordSet = new UnicodeSet();
41
42        fBurmeseWordSet.applyPattern("[[:Mymr:]&[:LineBreak=SA:]]");
43        fBurmeseWordSet.compact();
44
45        fMarkSet.applyPattern("[[:Mymr:]&[:LineBreak=SA:]&[:M:]]");
46        fMarkSet.add(0x0020);
47        fEndWordSet = new UnicodeSet(fBurmeseWordSet);
48        fBeginWordSet.add(0x1000, 0x102A);      // basic consonants and independent vowels
49
50        // Compact for caching
51        fMarkSet.compact();
52        fEndWordSet.compact();
53        fBeginWordSet.compact();
54
55        // Freeze the static UnicodeSet
56        fBurmeseWordSet.freeze();
57        fMarkSet.freeze();
58        fEndWordSet.freeze();
59        fBeginWordSet.freeze();
60    }
61
62    public BurmeseBreakEngine() throws IOException {
63        super(BreakIterator.KIND_WORD, BreakIterator.KIND_LINE);
64        setCharacters(fBurmeseWordSet);
65        // Initialize dictionary
66        fDictionary = DictionaryData.loadDictionaryFor("Mymr");
67    }
68
69    public boolean equals(Object obj) {
70        // Normally is a singleton, but it's possible to have duplicates
71        //   during initialization. All are equivalent.
72        return obj instanceof BurmeseBreakEngine;
73    }
74
75    public int hashCode() {
76        return getClass().hashCode();
77    }
78
79    public boolean handles(int c, int breakType) {
80        if (breakType == BreakIterator.KIND_WORD || breakType == BreakIterator.KIND_LINE) {
81            int script = UCharacter.getIntPropertyValue(c, UProperty.SCRIPT);
82            return (script == UScript.MYANMAR);
83        }
84        return false;
85    }
86
87    public int divideUpDictionaryRange(CharacterIterator fIter, int rangeStart, int rangeEnd,
88            DequeI foundBreaks) {
89
90
91        if ((rangeEnd - rangeStart) < BURMESE_MIN_WORD) {
92            return 0;  // Not enough characters for word
93        }
94        int wordsFound = 0;
95        int wordLength;
96        int current;
97        PossibleWord words[] = new PossibleWord[BURMESE_LOOKAHEAD];
98        for (int i = 0; i < BURMESE_LOOKAHEAD; i++) {
99            words[i] = new PossibleWord();
100        }
101        int uc;
102
103        fIter.setIndex(rangeStart);
104        while ((current = fIter.getIndex()) < rangeEnd) {
105            wordLength = 0;
106
107            //Look for candidate words at the current position
108            int candidates = words[wordsFound%BURMESE_LOOKAHEAD].candidates(fIter, fDictionary, rangeEnd);
109
110            // If we found exactly one, use that
111            if (candidates == 1) {
112                wordLength = words[wordsFound%BURMESE_LOOKAHEAD].acceptMarked(fIter);
113                wordsFound += 1;
114            }
115
116            // If there was more than one, see which one can take us forward the most words
117            else if (candidates > 1) {
118                boolean foundBest = false;
119                // If we're already at the end of the range, we're done
120                if (fIter.getIndex() < rangeEnd) {
121                    do {
122                        int wordsMatched = 1;
123                        if (words[(wordsFound+1)%BURMESE_LOOKAHEAD].candidates(fIter, fDictionary, rangeEnd) > 0) {
124                            if (wordsMatched < 2) {
125                                // Followed by another dictionary word; mark first word as a good candidate
126                                words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
127                                wordsMatched = 2;
128                            }
129
130                            // If we're already at the end of the range, we're done
131                            if (fIter.getIndex() >= rangeEnd) {
132                                break;
133                            }
134
135                            // See if any of the possible second words is followed by a third word
136                            do {
137                                // If we find a third word, stop right away
138                                if (words[(wordsFound+2)%BURMESE_LOOKAHEAD].candidates(fIter, fDictionary, rangeEnd) > 0) {
139                                    words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
140                                    foundBest = true;
141                                    break;
142                                }
143                            } while (words[(wordsFound+1)%BURMESE_LOOKAHEAD].backUp(fIter));
144                        }
145                    } while (words[wordsFound%BURMESE_LOOKAHEAD].backUp(fIter) && !foundBest);
146                }
147                wordLength = words[wordsFound%BURMESE_LOOKAHEAD].acceptMarked(fIter);
148                wordsFound += 1;
149            }
150
151            // We come here after having either found a word or not. We look ahead to the
152            // next word. If it's not a dictionary word, we will combine it with the word we
153            // just found (if there is one), but only if the preceding word does not exceed
154            // the threshold.
155            // The text iterator should now be positioned at the end of the word we found.
156            if (fIter.getIndex() < rangeEnd && wordLength < BURMESE_ROOT_COMBINE_THRESHOLD) {
157                // If it is a dictionary word, do nothing. If it isn't, then if there is
158                // no preceding word, or the non-word shares less than the minimum threshold
159                // of characters with a dictionary word, then scan to resynchronize
160                if (words[wordsFound%BURMESE_LOOKAHEAD].candidates(fIter, fDictionary, rangeEnd) <= 0 &&
161                        (wordLength == 0 ||
162                                words[wordsFound%BURMESE_LOOKAHEAD].longestPrefix() < BURMESE_PREFIX_COMBINE_THRESHOLD)) {
163                    // Look for a plausible word boundary
164                    int remaining = rangeEnd - (current + wordLength);
165                    int pc = fIter.current();
166                    int chars = 0;
167                    for (;;) {
168                        fIter.next();
169                        uc = fIter.current();
170                        chars += 1;
171                        if (--remaining <= 0) {
172                            break;
173                        }
174                        if (fEndWordSet.contains(pc) && fBeginWordSet.contains(uc)) {
175                            // Maybe. See if it's in the dictionary.
176                            int candidate = words[(wordsFound + 1) %BURMESE_LOOKAHEAD].candidates(fIter, fDictionary, rangeEnd);
177                            fIter.setIndex(current + wordLength + chars);
178                            if (candidate > 0) {
179                                break;
180                            }
181                        }
182                        pc = uc;
183                    }
184
185                    // Bump the word count if there wasn't already one
186                    if (wordLength <= 0) {
187                        wordsFound += 1;
188                    }
189
190                    // Update the length with the passed-over characters
191                    wordLength += chars;
192                } else {
193                    // Backup to where we were for next iteration
194                    fIter.setIndex(current+wordLength);
195                }
196            }
197
198            // Never stop before a combining mark.
199            int currPos;
200            while ((currPos = fIter.getIndex()) < rangeEnd && fMarkSet.contains(fIter.current())) {
201                fIter.next();
202                wordLength += fIter.getIndex() - currPos;
203            }
204
205            // Look ahead for possible suffixes if a dictionary word does not follow.
206            // We do this in code rather than using a rule so that the heuristic
207            // resynch continues to function. For example, one of the suffix characters
208            // could be a typo in the middle of a word.
209            // NOT CURRENTLY APPLICABLE TO BURMESE
210
211            // Did we find a word on this iteration? If so, push it on the break stack
212            if (wordLength > 0) {
213                foundBreaks.push(Integer.valueOf(current + wordLength));
214            }
215        }
216
217        // Don't return a break for the end of the dictionary range if there is one there
218        if (foundBreaks.peek() >= rangeEnd) {
219            foundBreaks.pop();
220            wordsFound -= 1;
221        }
222
223        return wordsFound;
224    }
225
226}
227