]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/text/RuleBasedBreakIterator.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / text / RuleBasedBreakIterator.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2005-2010 International Business Machines Corporation and          *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.text;\r
8 \r
9 import java.io.ByteArrayInputStream;\r
10 import java.io.ByteArrayOutputStream;\r
11 import java.io.IOException;\r
12 import java.io.InputStream;\r
13 import java.io.OutputStream;\r
14 import java.text.CharacterIterator;\r
15 \r
16 import com.ibm.icu.impl.Assert;\r
17 import com.ibm.icu.impl.ICUDebug;\r
18 \r
19 \r
20 /**\r
21  * Rule Based Break Iterator \r
22  * This is a port of the C++ class RuleBasedBreakIterator from ICU4C.\r
23  * \r
24  * @stable ICU 2.0\r
25  */\r
26 public class RuleBasedBreakIterator extends BreakIterator {\r
27 \r
28     \r
29     //=======================================================================\r
30     // Constructors & Factories\r
31     //=======================================================================\r
32     \r
33     /** \r
34      * @internal \r
35      * @deprecated This API is ICU internal only.\r
36      */\r
37     public RuleBasedBreakIterator() {\r
38     }\r
39 \r
40     /**\r
41      * Create a break iterator from a precompiled set of rules.\r
42      * @internal\r
43      * @deprecated This API is ICU internal only.\r
44      */\r
45     public static RuleBasedBreakIterator getInstanceFromCompiledRules(InputStream is) throws IOException {\r
46         RuleBasedBreakIterator  This = new RuleBasedBreakIterator();\r
47         This.fRData = RBBIDataWrapper.get(is);\r
48         return This;   \r
49     }\r
50     \r
51     /*private RuleBasedBreakIterator(RuleBasedBreakIterator other) {\r
52         // TODO: check types.\r
53         fRData = other.fRData;\r
54         if (fText != null) {\r
55             fText = (CharacterIterator)(other.fText.clone());   \r
56         }\r
57     }*/\r
58 \r
59     /**\r
60      * Construct a RuleBasedBreakIterator from a set of rules supplied as a string.\r
61      * @param rules The break rules to be used.\r
62      * @stable ICU 2.2\r
63      */\r
64     public RuleBasedBreakIterator(String rules)  {\r
65         init();\r
66         try {\r
67             ByteArrayOutputStream ruleOS = new ByteArrayOutputStream();\r
68             compileRules(rules, ruleOS);\r
69             byte [] ruleBA = ruleOS.toByteArray();\r
70             InputStream ruleIS = new ByteArrayInputStream(ruleBA);\r
71             fRData = RBBIDataWrapper.get(ruleIS);\r
72         } catch (IOException e) {\r
73             ///CLOVER:OFF\r
74             // An IO exception can only arrive here if there is a bug in the RBBI Rule compiler,\r
75             //  causing bogus compiled rules to be produced, but with no compile error raised.\r
76             RuntimeException rte = new RuntimeException("RuleBasedBreakIterator rule compilation internal error: "\r
77                     + e.getMessage());\r
78             throw rte;\r
79             ///CLOVER:ON\r
80         }\r
81     }\r
82     \r
83     \r
84     //=======================================================================\r
85     // Boilerplate\r
86     //=======================================================================\r
87     \r
88     /**\r
89      * Clones this iterator.\r
90      * @return A newly-constructed RuleBasedBreakIterator with the same\r
91      * behavior as this one.\r
92      * @stable ICU 2.0\r
93      */\r
94     public Object clone()\r
95     {\r
96         RuleBasedBreakIterator result = (RuleBasedBreakIterator)super.clone();\r
97         if (fText != null) {\r
98             result.fText = (CharacterIterator)(fText.clone());   \r
99         }\r
100         return result;\r
101     }\r
102 \r
103     /**\r
104      * Returns true if both BreakIterators are of the same class, have the same\r
105      * rules, and iterate over the same text.\r
106      * @stable ICU 2.0\r
107      */\r
108     public boolean equals(Object that) {\r
109         try {\r
110             RuleBasedBreakIterator other = (RuleBasedBreakIterator) that;\r
111             if (fRData != other.fRData && (fRData == null || other.fRData == null)) {System.out.println("GOT HERE");\r
112                 return false;\r
113             }\r
114             if (fRData != null && other.fRData != null && \r
115                     (!fRData.fRuleSource.equals(other.fRData.fRuleSource))) {\r
116                 return false;\r
117             }\r
118             if (fText == null && other.fText == null) {\r
119                 return true;   \r
120             }\r
121             if (fText == null || other.fText == null) {\r
122                 return false;   \r
123             }\r
124             return fText.equals(other.fText);\r
125         }\r
126         catch(ClassCastException e) {\r
127             return false;\r
128         }\r
129      }\r
130 \r
131     /**\r
132      * Returns the description (rules) used to create this iterator.\r
133      * (In ICU4C, the same function is RuleBasedBreakIterator::getRules())\r
134      * @stable ICU 2.0\r
135      */\r
136     public String toString() {\r
137         String   retStr = null;\r
138         if (fRData != null) {\r
139             retStr =  fRData.fRuleSource;\r
140         }\r
141         return retStr;\r
142     }\r
143 \r
144     /**\r
145      * Compute a hashcode for this BreakIterator\r
146      * @return A hash code\r
147      * @stable ICU 2.0\r
148      */\r
149     public int hashCode()\r
150     {\r
151         return fRData.fRuleSource.hashCode(); \r
152     }\r
153 \r
154     \r
155     /** \r
156      * Tag value for "words" that do not fit into any of other categories. \r
157      * Includes spaces and most punctuation. \r
158      * @draft ICU 3.0 \r
159      * @provisional This is a draft API and might change in a future release of ICU.\r
160      */\r
161     public static final int WORD_NONE           = 0;\r
162 \r
163     /**\r
164      * Upper bound for tags for uncategorized words. \r
165      * @draft ICU 3.0 \r
166      * @provisional This is a draft API and might change in a future release of ICU.\r
167      */\r
168     public static final int WORD_NONE_LIMIT     = 100;\r
169 \r
170     /**\r
171      * Tag value for words that appear to be numbers, lower limit. \r
172      * @draft ICU 3.0 \r
173      * @provisional This is a draft API and might change in a future release of ICU.\r
174      */\r
175     public static final int WORD_NUMBER         = 100;\r
176 \r
177     /** \r
178      * Tag value for words that appear to be numbers, upper limit.\r
179      * @draft ICU 3.0 \r
180      * @provisional This is a draft API and might change in a future release of ICU.\r
181      */\r
182     public static final int WORD_NUMBER_LIMIT   = 200;\r
183 \r
184     /** \r
185      * Tag value for words that contain letters, excluding\r
186      * hiragana, katakana or ideographic characters, lower limit. \r
187      * @draft ICU 3.0 \r
188      * @provisional This is a draft API and might change in a future release of ICU.\r
189      */\r
190     public static final int WORD_LETTER         = 200;\r
191 \r
192     /** \r
193      * Tag value for words containing letters, upper limit \r
194      * @draft ICU 3.0 \r
195      * @provisional This is a draft API and might change in a future release of ICU.\r
196      */\r
197     public static final int WORD_LETTER_LIMIT   = 300;\r
198 \r
199     /** \r
200      * Tag value for words containing kana characters, lower limit\r
201      * @draft ICU 3.0 \r
202      * @provisional This is a draft API and might change in a future release of ICU.\r
203      */\r
204     public static final int WORD_KANA           = 300;\r
205 \r
206     /** \r
207      * Tag value for words containing kana characters, upper limit\r
208      * @draft ICU 3.0 \r
209      * @provisional This is a draft API and might change in a future release of ICU.\r
210      */\r
211     public static final int WORD_KANA_LIMIT     = 400;\r
212 \r
213     /**\r
214      * Tag value for words containing ideographic characters, lower limit\r
215      * @draft ICU 3.0 \r
216      * @provisional This is a draft API and might change in a future release of ICU.\r
217      */\r
218     public static final int WORD_IDEO           = 400;\r
219 \r
220     /**\r
221      * Tag value for words containing ideographic characters, upper limit\r
222      * @draft ICU 3.0 \r
223      * @provisional This is a draft API and might change in a future release of ICU.\r
224      */\r
225     public static final int WORD_IDEO_LIMIT     = 500;\r
226 \r
227    \r
228     \r
229     \r
230     private static final int  START_STATE = 1;     // The state number of the starting state\r
231     private static final int  STOP_STATE  = 0;     // The state-transition value indicating "stop"\r
232     \r
233     // RBBIRunMode - the state machine runs an extra iteration at the beginning and end\r
234     //               of user text.  A variable with this enum type keeps track of where we\r
235     //               are.  The state machine only fetches user text input while in RUN mode.\r
236     private static final int  RBBI_START  = 0;\r
237     private static final int  RBBI_RUN    = 1;\r
238     private static final int  RBBI_END   = 2;\r
239 \r
240     /*\r
241      * The character iterator through which this BreakIterator accesses the text.\r
242      */\r
243     private CharacterIterator   fText = new java.text.StringCharacterIterator("");\r
244     \r
245     /**\r
246      * The rule data for this BreakIterator instance\r
247      * @internal\r
248      * @deprecated This API is ICU internal only.\r
249      */\r
250     protected RBBIDataWrapper     fRData;\r
251     \r
252     /*\r
253      * Index of the Rule {tag} values for the most recent match. \r
254      */\r
255     private int                 fLastRuleStatusIndex;\r
256 \r
257     /*\r
258      * Rule tag value valid flag.\r
259      * Some iterator operations don't intrinsically set the correct tag value.\r
260      * This flag lets us lazily compute the value if we are ever asked for it.\r
261      */\r
262     private boolean             fLastStatusIndexValid;\r
263 \r
264     /**\r
265      * Counter for the number of characters encountered with the "dictionary"\r
266      *   flag set.  Normal RBBI iterators don't use it, although the code\r
267      *   for updating it is live.  Dictionary Based break iterators (a subclass\r
268      *   of us) access this field directly.\r
269      * @internal\r
270      * @deprecated This API is ICU internal only.\r
271      */\r
272      protected int fDictionaryCharCount;\r
273 \r
274     /**\r
275      * Debugging flag.  Trace operation of state machine when true.\r
276      * @internal\r
277      * @deprecated This API is ICU internal only.\r
278      */\r
279     public static boolean       fTrace;\r
280 \r
281     /*\r
282      * ICU debug argument name for RBBI\r
283      */\r
284     private static final String RBBI_DEBUG_ARG = "rbbi";\r
285 \r
286     /**\r
287      * Dump the contents of the state table and character classes for this break iterator.\r
288      * For debugging only.\r
289      * @internal\r
290      * @deprecated This API is ICU internal only.\r
291      */\r
292     public void dump() {\r
293         this.fRData.dump();   \r
294     }\r
295 \r
296     private static boolean debugInitDone = false;\r
297     \r
298     private void init() {\r
299         fLastStatusIndexValid = true;\r
300         fDictionaryCharCount  = 0;\r
301 \r
302  \r
303         if (debugInitDone == false) {\r
304             fTrace = ICUDebug.enabled(RBBI_DEBUG_ARG)\r
305                 && ICUDebug.value(RBBI_DEBUG_ARG).indexOf("trace") >= 0;\r
306             debugInitDone = true;\r
307         }\r
308     }\r
309 \r
310     private static void compileRules(String rules, OutputStream ruleBinary) throws IOException {\r
311         RBBIRuleBuilder.compileRules(rules, ruleBinary);\r
312     }\r
313     \r
314     //=======================================================================\r
315     // BreakIterator overrides\r
316     //=======================================================================\r
317 \r
318     /**\r
319      * Sets the current iteration position to the beginning of the text.\r
320      * (i.e., the CharacterIterator's starting offset).\r
321      * @return The offset of the beginning of the text.\r
322      * @stable ICU 2.0\r
323      */\r
324     public int first() {\r
325         fLastRuleStatusIndex  = 0;\r
326         fLastStatusIndexValid = true;\r
327         if (fText == null) {\r
328             return BreakIterator.DONE;\r
329         }\r
330         fText.first();\r
331         return fText.getIndex();\r
332     }\r
333     \r
334     \r
335     /**\r
336      * Sets the current iteration position to the end of the text.\r
337      * (i.e., the CharacterIterator's ending offset).\r
338      * @return The text's past-the-end offset.\r
339      * @stable ICU 2.0\r
340      */\r
341     public int last() {\r
342         if (fText == null) {\r
343             fLastRuleStatusIndex  = 0;\r
344             fLastStatusIndexValid = true;\r
345             return BreakIterator.DONE;\r
346         }\r
347 \r
348         // I'm not sure why, but t.last() returns the offset of the last character,\r
349         // rather than the past-the-end offset\r
350         //\r
351         //   (It's so a loop like for(p=it.last(); p!=DONE; p=it.previous()) ...\r
352         //     will work correctly.)\r
353 \r
354 \r
355         fLastStatusIndexValid = false;\r
356         int pos = fText.getEndIndex();\r
357         fText.setIndex(pos);\r
358         return pos;\r
359     }\r
360     \r
361     \r
362     /**\r
363      * Advances the iterator either forward or backward the specified number of steps.\r
364      * Negative values move backward, and positive values move forward.  This is\r
365      * equivalent to repeatedly calling next() or previous().\r
366      * @param n The number of steps to move.  The sign indicates the direction\r
367      * (negative is backwards, and positive is forwards).\r
368      * @return The character offset of the boundary position n boundaries away from\r
369      * the current one.\r
370      * @stable ICU 2.0\r
371      */\r
372     public int next(int n) {\r
373         int result = current();\r
374         while (n > 0) {\r
375             result = handleNext();\r
376             --n;\r
377         }\r
378         while (n < 0) {\r
379             result = previous();\r
380             ++n;\r
381         }\r
382         return result;\r
383     }\r
384     \r
385     \r
386     /**\r
387      * Advances the iterator to the next boundary position.\r
388      * @return The position of the first boundary after this one.\r
389      * @stable ICU 2.0\r
390      */\r
391     public int next() {\r
392         return handleNext();\r
393     }\r
394     \r
395     \r
396     /**\r
397      * Moves the iterator backwards, to the last boundary preceding this one.\r
398      * @return The position of the last boundary position preceding this one.\r
399      * @stable ICU 2.0\r
400      */\r
401     public int previous() {\r
402         // if we're already sitting at the beginning of the text, return DONE\r
403         if (fText == null || current() == fText.getBeginIndex()) {\r
404             fLastRuleStatusIndex  = 0;\r
405             fLastStatusIndexValid = true;\r
406             return BreakIterator.DONE;\r
407         }\r
408 \r
409         if (fRData.fSRTable != null || fRData.fSFTable != null) {\r
410             return handlePrevious(fRData.fRTable);\r
411         }\r
412 \r
413         // old rule syntax\r
414         // set things up.  handlePrevious() will back us up to some valid\r
415         // break position before the current position (we back our internal\r
416         // iterator up one step to prevent handlePrevious() from returning\r
417         // the current position), but not necessarily the last one before\r
418         // where we started\r
419 \r
420         int       start = current();\r
421 \r
422         CIPrevious32(fText);\r
423         int       lastResult    = handlePrevious(fRData.fRTable);\r
424         if (lastResult == BreakIterator.DONE) {\r
425             lastResult = fText.getBeginIndex();\r
426             fText.setIndex(lastResult);\r
427         }\r
428         int       result        = lastResult;\r
429         int       lastTag       = 0;\r
430         boolean   breakTagValid = false;\r
431 \r
432         // iterate forward from the known break position until we pass our\r
433         // starting point.  The last break position before the starting\r
434         // point is our return value\r
435 \r
436         for (;;) {\r
437             result         = handleNext();\r
438             if (result == BreakIterator.DONE || result >= start) {\r
439                 break;\r
440             }\r
441             lastResult     = result;\r
442             lastTag        = fLastRuleStatusIndex;\r
443             breakTagValid  = true;\r
444         }\r
445 \r
446         // fLastBreakTag wants to have the value for section of text preceding\r
447         // the result position that we are to return (in lastResult.)  If\r
448         // the backwards rules overshot and the above loop had to do two or more\r
449         // handleNext()s to move up to the desired return position, we will have a valid\r
450         // tag value. But, if handlePrevious() took us to exactly the correct result positon,\r
451         // we wont have a tag value for that position, which is only set by handleNext().\r
452 \r
453         // set the current iteration position to be the last break position\r
454         // before where we started, and then return that value\r
455         fText.setIndex(lastResult);\r
456         fLastRuleStatusIndex  = lastTag;       // for use by getRuleStatus()\r
457         fLastStatusIndexValid = breakTagValid;\r
458         return lastResult;\r
459     }\r
460     /**\r
461      * Sets the iterator to refer to the first boundary position following\r
462      * the specified position.\r
463      * @param offset The position from which to begin searching for a break position.\r
464      * @return The position of the first break after the current position.\r
465      * @stable ICU 2.0\r
466      */\r
467     public int following(int offset) {\r
468         // if the offset passed in is already past the end of the text,\r
469         // just return DONE; if it's before the beginning, return the\r
470         // text's starting offset\r
471         fLastRuleStatusIndex  = 0;\r
472         fLastStatusIndexValid = true;\r
473         if (fText == null || offset >= fText.getEndIndex()) {\r
474             last();\r
475             return next();\r
476         }\r
477         else if (offset < fText.getBeginIndex()) {\r
478             return first();\r
479         }\r
480 \r
481         // otherwise, set our internal iteration position (temporarily)\r
482         // to the position passed in.  If this is the _beginning_ position,\r
483         // then we can just use next() to get our return value\r
484 \r
485         int result = 0;\r
486 \r
487         if (fRData.fSRTable != null) {\r
488             // Safe Point Reverse rules exist.\r
489             //   This allows us to use the optimum algorithm.\r
490             fText.setIndex(offset);\r
491             // move forward one codepoint to prepare for moving back to a\r
492             // safe point.\r
493             // this handles offset being between a supplementary character\r
494             CINext32(fText);\r
495             // handlePrevious will move most of the time to < 1 boundary away\r
496             handlePrevious(fRData.fSRTable);\r
497             result = next();\r
498             while (result <= offset) {\r
499                 result = next();\r
500             }\r
501             return result;\r
502         }\r
503         if (fRData.fSFTable != null) {\r
504             // No Safe point reverse table, but there is a safe pt forward table.\r
505             // \r
506             fText.setIndex(offset);\r
507             CIPrevious32(fText);\r
508             // handle next will give result >= offset\r
509             handleNext(fRData.fSFTable);\r
510             // previous will give result 0 or 1 boundary away from offset,\r
511             // most of the time\r
512             // we have to\r
513             int oldresult = previous();\r
514             while (oldresult > offset) {\r
515                 result = previous();\r
516                 if (result <= offset) {\r
517                     return oldresult;\r
518                 }\r
519                 oldresult = result;\r
520             }\r
521             result = next();\r
522             if (result <= offset) {\r
523                 return next();\r
524             }\r
525             return result;\r
526         }\r
527         // otherwise, we have to sync up first.  Use handlePrevious() to back\r
528         // us up to a known break position before the specified position (if\r
529         // we can determine that the specified position is a break position,\r
530         // we don't back up at all).  This may or may not be the last break\r
531         // position at or before our starting position.  Advance forward\r
532         // from here until we've passed the starting position.  The position\r
533         // we stop on will be the first break position after the specified one.\r
534         // old rule syntax\r
535 \r
536         fText.setIndex(offset);\r
537         if (offset == fText.getBeginIndex()) {\r
538             return handleNext();\r
539         }\r
540         result = previous();\r
541 \r
542         while (result != BreakIterator.DONE && result <= offset) {\r
543             result = next();\r
544         }\r
545 \r
546         return result;\r
547     }\r
548     /**\r
549      * Sets the iterator to refer to the last boundary position before the\r
550      * specified position.\r
551      * @param offset The position to begin searching for a break from.\r
552      * @return The position of the last boundary before the starting position.\r
553      * @stable ICU 2.0\r
554      */\r
555     public int preceding(int offset) {\r
556         // if the offset passed in is already past the end of the text,\r
557         // just return DONE; if it's before the beginning, return the\r
558 \r
559         // text's starting offset\r
560         if (fText == null || offset > fText.getEndIndex()) {\r
561             // return BreakIterator::DONE;\r
562             return last();\r
563         }\r
564         else if (offset < fText.getBeginIndex()) {\r
565             return first();\r
566         }\r
567 \r
568         // if we start by updating the current iteration position to the\r
569         // position specified by the caller, we can just use previous()\r
570         // to carry out this operation\r
571 \r
572         int  result;\r
573         if (fRData.fSFTable != null) {\r
574             /// todo synwee\r
575             // new rule syntax\r
576             fText.setIndex(offset);\r
577             // move backwards one codepoint to prepare for moving forwards to a\r
578             // safe point.\r
579             // this handles offset being between a supplementary character\r
580             CIPrevious32(fText);\r
581             handleNext(fRData.fSFTable);\r
582             result = previous();\r
583             while (result >= offset) {\r
584                 result = previous();\r
585             }\r
586             return result;\r
587         }\r
588         if (fRData.fSRTable != null) {\r
589             // backup plan if forward safe table is not available\r
590             fText.setIndex(offset);\r
591             CINext32(fText);\r
592             // handle previous will give result <= offset\r
593             handlePrevious(fRData.fSRTable);\r
594 \r
595             // next will give result 0 or 1 boundary away from offset,\r
596             // most of the time\r
597             // we have to\r
598             int oldresult = next();\r
599             while (oldresult < offset) {\r
600                 result = next();\r
601                 if (result >= offset) {\r
602                     return oldresult;\r
603                 }\r
604                 oldresult = result;\r
605             }\r
606             result = previous();\r
607             if (result >= offset) {\r
608                 return previous();\r
609             }\r
610             return result;\r
611         }\r
612 \r
613         // old rule syntax\r
614         fText.setIndex(offset);\r
615         return previous();\r
616     }\r
617 \r
618     /**\r
619      * Throw IllegalArgumentException unless begin <= offset < end.\r
620      * @stable ICU 2.0\r
621      */\r
622     protected static final void checkOffset(int offset, CharacterIterator text) {\r
623         if (offset < text.getBeginIndex() || offset > text.getEndIndex()) {\r
624             throw new IllegalArgumentException("offset out of bounds");\r
625         }\r
626     }\r
627 \r
628 \r
629 /**\r
630  * Returns true if the specfied position is a boundary position.  As a side\r
631  * effect, leaves the iterator pointing to the first boundary position at\r
632  * or after "offset".\r
633  * @param offset the offset to check.\r
634  * @return True if "offset" is a boundary position.\r
635  * @stable ICU 2.0\r
636  */\r
637 public boolean isBoundary(int offset) {\r
638     checkOffset(offset, fText);\r
639     \r
640     // the beginning index of the iterator is always a boundary position by definition\r
641     if (offset == fText.getBeginIndex()) {\r
642         first();       // For side effects on current position, tag values.\r
643         return true;\r
644     }\r
645 \r
646     if (offset == fText.getEndIndex()) {\r
647         last();       // For side effects on current position, tag values.\r
648         return true;\r
649     }\r
650 \r
651     // otherwise, we can use following() on the position before the specified\r
652     // one and return true if the position we get back is the one the user\r
653     // specified\r
654     \r
655     // return following(offset - 1) == offset;\r
656     // TODO:  check whether it is safe to revert to the simpler offset-1 code\r
657     //         The safe rules may take care of unpaired surrogates ok.\r
658     fText.setIndex(offset);\r
659     CIPrevious32(fText);\r
660     int  pos = fText.getIndex();\r
661     boolean result = following(pos) == offset;\r
662     return result;\r
663 }\r
664 \r
665 /**\r
666  * Returns the current iteration position.\r
667  * @return The current iteration position.\r
668  * @stable ICU 2.0\r
669  */\r
670 public int current() {\r
671     return (fText != null) ? fText.getIndex() : BreakIterator.DONE;\r
672     }\r
673 \r
674 \r
675 \r
676 private void makeRuleStatusValid() {\r
677     if (fLastStatusIndexValid == false) {\r
678         //  No cached status is available.\r
679         if (fText == null || current() == fText.getBeginIndex()) {\r
680             //  At start of text, or there is no text.  Status is always zero.\r
681             fLastRuleStatusIndex = 0;\r
682             fLastStatusIndexValid = true;\r
683         } else {\r
684             //  Not at start of text.  Find status the tedious way.\r
685             int pa = current();\r
686             previous();\r
687             int pb = next();\r
688             Assert.assrt (pa == pb);\r
689         }\r
690         Assert.assrt(fLastStatusIndexValid == true);\r
691         Assert.assrt(fLastRuleStatusIndex >= 0  &&  fLastRuleStatusIndex < fRData.fStatusTable.length);\r
692     }\r
693 }\r
694 \r
695 \r
696 /**\r
697  * Return the status tag from the break rule that determined the most recently\r
698  * returned break position.  The values appear in the rule source\r
699  * within brackets, {123}, for example.  For rules that do not specify a\r
700  * status, a default value of 0 is returned.  If more than one rule applies,\r
701  * the numerically largest of the possible status values is returned.\r
702  * <p>\r
703  * Of the standard types of ICU break iterators, only the word break\r
704  * iterator provides status values.  The values are defined in\r
705  * class RuleBasedBreakIterator, and allow distinguishing between words\r
706  * that contain alphabetic letters, "words" that appear to be numbers,\r
707  * punctuation and spaces, words containing ideographic characters, and\r
708  * more.  Call <code>getRuleStatus</code> after obtaining a boundary\r
709  * position from <code>next()<code>, <code>previous()</code>, or \r
710  * any other break iterator functions that returns a boundary position.\r
711  * <p>\r
712  * @return the status from the break rule that determined the most recently\r
713  * returned break position.\r
714  *\r
715  * @draft ICU 3.0\r
716  * @provisional This is a draft API and might change in a future release of ICU.\r
717  */\r
718 \r
719 public int  getRuleStatus() {\r
720     makeRuleStatusValid();\r
721     //   Status records have this form:\r
722     //           Count N         <--  fLastRuleStatusIndex points here.\r
723     //           Status val 0\r
724     //           Status val 1\r
725     //              ...\r
726     //           Status val N-1  <--  the value we need to return\r
727     //   The status values are sorted in ascending order.\r
728     //   This function returns the last (largest) of the array of status values.\r
729     int  idx = fLastRuleStatusIndex + fRData.fStatusTable[fLastRuleStatusIndex];\r
730     int  tagVal = fRData.fStatusTable[idx];\r
731 \r
732     return tagVal;\r
733 }\r
734 \r
735 \r
736 \r
737 /**\r
738  * Get the status (tag) values from the break rule(s) that determined the most \r
739  * recently returned break position.  The values appear in the rule source\r
740  * within brackets, {123}, for example.  The default status value for rules\r
741  * that do not explicitly provide one is zero.\r
742  * <p>\r
743  * The status values used by the standard ICU break rules are defined\r
744  * as public constants in class RuleBasedBreakIterator.\r
745  * <p>\r
746  * If the size  of the output array is insufficient to hold the data,\r
747  *  the output will be truncated to the available length.  No exception\r
748  *  will be thrown.\r
749  *\r
750  * @param fillInArray an array to be filled in with the status values.  \r
751  * @return          The number of rule status values from rules that determined \r
752  *                  the most recent boundary returned by the break iterator.\r
753  *                  In the event that the array is too small, the return value\r
754  *                  is the total number of status values that were available,\r
755  *                  not the reduced number that were actually returned.\r
756  * @draft ICU 3.0\r
757  * @provisional This is a draft API and might change in a future release of ICU.\r
758  */\r
759 public int getRuleStatusVec(int[] fillInArray) {\r
760     makeRuleStatusValid();\r
761     int numStatusVals = fRData.fStatusTable[fLastRuleStatusIndex];\r
762     if (fillInArray != null) {  \r
763         int numToCopy = Math.min(numStatusVals, fillInArray.length);\r
764         for (int i=0; i<numToCopy; i++) {\r
765             fillInArray[i] = fRData.fStatusTable[fLastRuleStatusIndex + i + 1];\r
766         }\r
767     }\r
768     return numStatusVals;\r
769  }\r
770 \r
771 \r
772 /**\r
773  * Return a CharacterIterator over the text being analyzed.  This version\r
774  * of this method returns the actual CharacterIterator we're using internally.\r
775  * Changing the state of this iterator can have undefined consequences.  If\r
776  * you need to change it, clone it first.\r
777  * @return An iterator over the text being analyzed.\r
778  * @stable ICU 2.0\r
779  */\r
780     public CharacterIterator getText() {\r
781         return fText;\r
782     }\r
783 \r
784 \r
785     /**\r
786      * Set the iterator to analyze a new piece of text.  This function resets\r
787      * the current iteration position to the beginning of the text.\r
788      * @param newText An iterator over the text to analyze.\r
789      * @stable ICU 2.0\r
790      */\r
791     public void setText(CharacterIterator newText) {\r
792         fText = newText;\r
793         this.first();\r
794     }\r
795     \r
796     /**\r
797      * Control debug, trace and dump options.\r
798      * @internal\r
799      * @deprecated This API is ICU internal only.\r
800      */\r
801     protected static String fDebugEnv = ICUDebug.enabled(RBBI_DEBUG_ARG) ?\r
802                                         ICUDebug.value(RBBI_DEBUG_ARG) : null;\r
803 \r
804     \r
805     // 32 bit Char value returned from when an iterator has run out of range.\r
806     //     Positive value so fast case (not end, not surrogate) can be checked\r
807     //     with a single test.\r
808     private static int CI_DONE32 = 0x7fffffff;\r
809     \r
810     /**\r
811      * Move the iterator forward to the next code point, and return that code point,\r
812      *   leaving the iterator positioned at char returned.\r
813      *   For Supplementary chars, the iterator is left positioned at the lead surrogate.\r
814      * @param ci  The character iterator\r
815      * @return    The next code point.\r
816      */\r
817      static int CINext32(CharacterIterator ci) {\r
818         // If the current position is at a surrogate pair, move to the trail surrogate\r
819         //   which leaves it in positon for underlying iterator's next() to work.\r
820         int c= ci.current();\r
821         if (c >= UTF16.LEAD_SURROGATE_MIN_VALUE && c<=UTF16.LEAD_SURROGATE_MAX_VALUE) {\r
822             c = ci.next();   \r
823             if (c<UTF16.TRAIL_SURROGATE_MIN_VALUE || c>UTF16.TRAIL_SURROGATE_MAX_VALUE) {\r
824                c = ci.previous();   \r
825             }\r
826         }\r
827 \r
828         // For BMP chars, this next() is the real deal.\r
829         c = ci.next();\r
830         \r
831         // If we might have a lead surrogate, we need to peak ahead to get the trail \r
832         //  even though we don't want to really be positioned there.\r
833         if (c >= UTF16.LEAD_SURROGATE_MIN_VALUE) {\r
834             c = CINextTrail32(ci, c);   \r
835         }\r
836         \r
837         if (c >= UTF16.SUPPLEMENTARY_MIN_VALUE && c != CI_DONE32) {\r
838             // We got a supplementary char.  Back the iterator up to the postion\r
839             // of the lead surrogate.\r
840             ci.previous();   \r
841         }\r
842         return c;\r
843    }\r
844 \r
845     \r
846     // Out-of-line portion of the in-line Next32 code.\r
847     // The call site does an initial ci.next() and calls this function\r
848     //    if the 16 bit value it gets is >= LEAD_SURROGATE_MIN_VALUE.\r
849     // NOTE:  we leave the underlying char iterator positioned in the\r
850     //        middle of a surroage pair.  ci.next() will work correctly\r
851     //        from there, but the ci.getIndex() will be wrong, and needs\r
852     //        adjustment.\r
853     private static int CINextTrail32(CharacterIterator ci, int lead) {\r
854         int retVal = lead;\r
855         if (lead <= UTF16.LEAD_SURROGATE_MAX_VALUE) {\r
856             char  cTrail = ci.next();\r
857             if (UTF16.isTrailSurrogate(cTrail)) {\r
858                 retVal = ((lead  - UTF16.LEAD_SURROGATE_MIN_VALUE) << 10) +\r
859                             (cTrail - UTF16.TRAIL_SURROGATE_MIN_VALUE) +\r
860                             UTF16.SUPPLEMENTARY_MIN_VALUE;\r
861             } else {\r
862                 ci.previous();\r
863             }\r
864         } else {\r
865             if (lead == CharacterIterator.DONE && ci.getIndex() >= ci.getEndIndex()) {\r
866                 retVal = CI_DONE32;\r
867             }\r
868         }\r
869         return retVal;\r
870     }\r
871        \r
872     private static int CIPrevious32(CharacterIterator ci) {\r
873         if (ci.getIndex() <= ci.getBeginIndex()) {\r
874             return CI_DONE32;   \r
875         }\r
876         char trail = ci.previous();\r
877         int retVal = trail;\r
878         if (UTF16.isTrailSurrogate(trail) && ci.getIndex()>ci.getBeginIndex()) {\r
879             char lead = ci.previous();\r
880             if (UTF16.isLeadSurrogate(lead)) {\r
881                 retVal = (((int)lead  - UTF16.LEAD_SURROGATE_MIN_VALUE) << 10) +\r
882                           ((int)trail - UTF16.TRAIL_SURROGATE_MIN_VALUE) +\r
883                           UTF16.SUPPLEMENTARY_MIN_VALUE;\r
884             } else {\r
885                 ci.next();\r
886             }           \r
887         }\r
888         return retVal;\r
889     }\r
890    \r
891     static int CICurrent32(CharacterIterator ci) {\r
892         char  lead   = ci.current();\r
893         int   retVal = lead;\r
894         if (retVal < UTF16.LEAD_SURROGATE_MIN_VALUE) {\r
895             return retVal;   \r
896         }\r
897         if (UTF16.isLeadSurrogate(lead)) {\r
898             int  trail = (int)ci.next();\r
899             ci.previous();\r
900             if (UTF16.isTrailSurrogate((char)trail)) {\r
901                 retVal = ((lead  - UTF16.LEAD_SURROGATE_MIN_VALUE) << 10) +\r
902                          (trail - UTF16.TRAIL_SURROGATE_MIN_VALUE) +\r
903                          UTF16.SUPPLEMENTARY_MIN_VALUE;\r
904             }\r
905          } else {\r
906             if (lead == CharacterIterator.DONE) {\r
907                 if (ci.getIndex() >= ci.getEndIndex())   {\r
908                     retVal = CI_DONE32;   \r
909                 }\r
910             }\r
911          }\r
912         return retVal;\r
913     }\r
914     \r
915 \r
916     //-----------------------------------------------------------------------------------\r
917     //\r
918     //      handleNext(void)    All forward iteration vectors through this function.\r
919     //                          NOTE:  This function is overridden by the dictionary base break iterator.\r
920     //                                 User level API functions go to the dbbi implementation\r
921     //                                     when the break iterator type is dbbi.\r
922     //                                 The DBBI implementation sometimes explicitly calls back to here, \r
923     //                                     its inherited handleNext().\r
924     //                      \r
925     //-----------------------------------------------------------------------------------\r
926     int handleNext() {\r
927         return handleNext(fRData.fFTable);\r
928     }\r
929 \r
930     /**\r
931      * The State Machine Engine for moving forward is here.\r
932      * This function is the heart of the RBBI run time engine.\r
933      * \r
934      * @param stateTable\r
935      * @return the new iterator position\r
936      * \r
937      * A note on supplementary characters and the position of underlying\r
938      * Java CharacterIterator:   Normally, a character iterator is positioned at\r
939      * the char most recently returned by next().  Within this function, when\r
940      * a supplementary char is being processed, the char iterator is left\r
941      * sitting on the trail surrogate, in the middle of the code point.\r
942      * This is different from everywhere else, where an iterator always\r
943      * points at the lead surrogate of a supplementary.\r
944      */\r
945     private int handleNext(short stateTable[]) {\r
946         int               state;\r
947         short             category        = 0;\r
948         int               mode;\r
949         int               row;\r
950         int               c;\r
951         int               lookaheadStatus = 0;\r
952         int               lookaheadTagIdx = 0;\r
953         int               result          = 0;\r
954         int               initialPosition = 0;\r
955         int               lookaheadResult = 0;\r
956         boolean          lookAheadHardBreak = \r
957             (stateTable[RBBIDataWrapper.FLAGS+1] & RBBIDataWrapper.RBBI_LOOKAHEAD_HARD_BREAK) != 0;\r
958         \r
959         if (fTrace) {\r
960             System.out.println("Handle Next   pos      char  state category");\r
961         }\r
962 \r
963         // No matter what, handleNext alway correctly sets the break tag value.\r
964         fLastStatusIndexValid = true;\r
965         fLastRuleStatusIndex  = 0;\r
966 \r
967         // if we're already at the end of the text, return DONE.\r
968         if (fText == null) {\r
969             fLastRuleStatusIndex = 0;\r
970             return BreakIterator.DONE;\r
971         }\r
972 \r
973         // Set up the starting char\r
974         initialPosition = fText.getIndex();\r
975         result          = initialPosition;\r
976         c               = fText.current();\r
977         if (c >= UTF16.LEAD_SURROGATE_MIN_VALUE) {\r
978             c = CINextTrail32(fText, c);\r
979             if (c == CI_DONE32) {\r
980                 fLastRuleStatusIndex = 0;\r
981                 return BreakIterator.DONE;\r
982             }\r
983         }\r
984 \r
985         // Set the initial state for the state machine\r
986         state           = START_STATE;\r
987         row             = fRData.getRowIndex(state); \r
988         category        = 3;\r
989         mode            = RBBI_RUN;\r
990         if ((stateTable[RBBIDataWrapper.FLAGS+1] & RBBIDataWrapper.RBBI_BOF_REQUIRED) != 0) {\r
991             category = 2;\r
992             mode     = RBBI_START;\r
993         }\r
994 \r
995 \r
996         // loop until we reach the end of the text or transition to state 0\r
997         while (state != STOP_STATE) {\r
998             if (c == CI_DONE32) {\r
999                 // Reached end of input string.\r
1000                 if (mode == RBBI_END) {\r
1001                     // We have already run the loop one last time with the\r
1002                     // character set to the pseudo {eof} value. Now it is time\r
1003                     // to unconditionally bail out.\r
1004 \r
1005                     if (lookaheadResult > result) {\r
1006                         // We ran off the end of the string with a pending\r
1007                         // look-ahead match.\r
1008                         // Treat this as if the look-ahead condition had been\r
1009                         // met, and return\r
1010                         // the match at the / position from the look-ahead rule.\r
1011                         result = lookaheadResult;\r
1012                         fLastRuleStatusIndex = lookaheadTagIdx;\r
1013                         lookaheadStatus = 0;\r
1014                     } else if (result == initialPosition) {\r
1015                         // Ran off end, no match found.\r
1016                         // move forward one\r
1017                         fText.setIndex(initialPosition);\r
1018                         CINext32(fText);\r
1019                     }\r
1020                     break;\r
1021                 }\r
1022                 // Run the loop one last time with the fake end-of-input character category\r
1023                 mode = RBBI_END;\r
1024                 category = 1;\r
1025             }\r
1026             \r
1027             // Get the char category.  An incoming category of 1 or 2 mens that\r
1028             //      we are preset for doing the beginning or end of input, and\r
1029             //      that we shouldn't get a category from an actual text input character.\r
1030             //\r
1031             if (mode == RBBI_RUN) {\r
1032                 // look up the current character's character category, which tells us\r
1033                 // which column in the state table to look at.\r
1034                 //\r
1035                 category = (short) fRData.fTrie.getCodePointValue(c);\r
1036                 \r
1037                 // Check the dictionary bit in the character's category.\r
1038                 //    Counter is only used by dictionary based iterators (subclasses).\r
1039                 //    Chars that need to be handled by a dictionary have a flag bit set\r
1040                 //    in their category values.\r
1041                 //\r
1042                 if ((category & 0x4000) != 0)  {\r
1043                     fDictionaryCharCount++;\r
1044                     //  And off the dictionary flag bit.\r
1045                     category &= ~0x4000;\r
1046                 }\r
1047            }\r
1048 \r
1049             if (fTrace) {\r
1050                 System.out.print("            " +  RBBIDataWrapper.intToString(fText.getIndex(), 5)); \r
1051                 System.out.print(RBBIDataWrapper.intToHexString(c, 10));\r
1052                 System.out.println(RBBIDataWrapper.intToString(state,7) + RBBIDataWrapper.intToString(category,6));\r
1053             }\r
1054 \r
1055             // look up a state transition in the state table\r
1056             //     state = row->fNextState[category];\r
1057             state = stateTable[row + RBBIDataWrapper.NEXTSTATES + category];\r
1058             row   = fRData.getRowIndex(state);  \r
1059 \r
1060             // Advance to the next character.  \r
1061             // If this is a beginning-of-input loop iteration, don't advance.\r
1062             //    The next iteration will be processing the first real input character.\r
1063             if (mode == RBBI_RUN) {\r
1064                 c = (int)fText.next(); \r
1065                 if (c >= UTF16.LEAD_SURROGATE_MIN_VALUE) {\r
1066                     c = CINextTrail32(fText, c);\r
1067                 }\r
1068             } else {\r
1069                 if (mode == RBBI_START) {\r
1070                     mode = RBBI_RUN;\r
1071                 }\r
1072             }\r
1073              \r
1074             if (stateTable[row + RBBIDataWrapper.ACCEPTING] == -1) {\r
1075                 // Match found, common case\r
1076                 result = fText.getIndex();\r
1077                 if (c >= UTF16.SUPPLEMENTARY_MIN_VALUE && c != CI_DONE32) {\r
1078                     // The iterator has been left in the middle of a surrogate pair.\r
1079                     // We want the start of it.\r
1080                     result--;\r
1081                 }\r
1082 \r
1083                 //  Remember the break status (tag) values.\r
1084                 fLastRuleStatusIndex = stateTable[row + RBBIDataWrapper.TAGIDX];\r
1085             }\r
1086 \r
1087             if (stateTable[row + RBBIDataWrapper.LOOKAHEAD] != 0) {\r
1088                 if (lookaheadStatus != 0\r
1089                     && stateTable[row + RBBIDataWrapper.ACCEPTING] == lookaheadStatus) {\r
1090                     // Lookahead match is completed.  Set the result accordingly, but only\r
1091                     // if no other rule has matched further in the mean time.\r
1092                     result               = lookaheadResult;\r
1093                     fLastRuleStatusIndex = lookaheadTagIdx;\r
1094                     lookaheadStatus      = 0;\r
1095                     // TODO: make a standalone hard break in a rule work.\r
1096                     if (lookAheadHardBreak) {\r
1097                         return result;\r
1098                     }\r
1099                     // Look-ahead completed, but other rules may match further.  Continue on.\r
1100                     //   TODO:  junk this feature?  I don't think it's used anywhere.\r
1101                     continue;\r
1102                 }\r
1103 \r
1104                 lookaheadResult = fText.getIndex();\r
1105                 if (c>=UTF16.SUPPLEMENTARY_MIN_VALUE && c!=CI_DONE32) {\r
1106                     // The iterator has been left in the middle of a surrogate pair.\r
1107                     // We want the beginning  of it.\r
1108                     lookaheadResult--;\r
1109                 }\r
1110                 lookaheadStatus = stateTable[row + RBBIDataWrapper.LOOKAHEAD];\r
1111                 lookaheadTagIdx = stateTable[row + RBBIDataWrapper.TAGIDX];\r
1112                 continue;\r
1113             }\r
1114 \r
1115 \r
1116             if (stateTable[row + RBBIDataWrapper.ACCEPTING] != 0) {\r
1117                 // Because this is an accepting state, any in-progress look-ahead match\r
1118                 //   is no longer relavant.  Clear out the pending lookahead status.\r
1119                 lookaheadStatus = 0; \r
1120             }\r
1121             \r
1122          }        // End of state machine main loop\r
1123 \r
1124         // The state machine is done.  Check whether it found a match...\r
1125 \r
1126         // If the iterator failed to advance in the match engine, force it ahead by one.\r
1127         //   (This really indicates a defect in the break rules.  They should always match\r
1128         //    at least one character.)\r
1129         if (result == initialPosition) {\r
1130             result = fText.setIndex(initialPosition);\r
1131             CINext32(fText);\r
1132             result = fText.getIndex();\r
1133         }\r
1134 \r
1135         // Leave the iterator at our result position.\r
1136         //   (we may have advanced beyond the last accepting position chasing after\r
1137         //    longer matches that never completed.)\r
1138         fText.setIndex(result);\r
1139         if (fTrace) {\r
1140             System.out.println("result = " + result);\r
1141         }\r
1142         return result;\r
1143     }\r
1144 \r
1145     \r
1146     \r
1147     private int handlePrevious(short stateTable[]) {\r
1148         int            state;\r
1149         int            category           = 0;\r
1150         int            mode;\r
1151         int            row;        \r
1152         int            c;\r
1153         int            lookaheadStatus    = 0;\r
1154         int            result             = 0;\r
1155         int            initialPosition    = 0;\r
1156         int            lookaheadResult    = 0;\r
1157         boolean        lookAheadHardBreak = \r
1158             (stateTable[RBBIDataWrapper.FLAGS+1] & RBBIDataWrapper.RBBI_LOOKAHEAD_HARD_BREAK) != 0;\r
1159         \r
1160         \r
1161         if (fText == null || stateTable == null) {\r
1162             return 0;\r
1163         }\r
1164         // handlePrevious() never gets the rule status.\r
1165         // Flag the status as invalid; if the user ever asks for status, we will need\r
1166         // to back up, then re-find the break position using handleNext(), which does\r
1167         // get the status value.\r
1168         fLastStatusIndexValid = false;\r
1169         fLastRuleStatusIndex  = 0;\r
1170         \r
1171         // set up the starting char\r
1172         initialPosition = fText.getIndex();\r
1173         result          = initialPosition;\r
1174         c               = CIPrevious32(fText);\r
1175         \r
1176         // Set up the initial state for the state machine\r
1177         state = START_STATE;\r
1178         row = fRData.getRowIndex(state);\r
1179         category = 3;   // TODO:  obsolete?  from the old start/run mode scheme?\r
1180         mode     = RBBI_RUN;\r
1181         if ((stateTable[RBBIDataWrapper.FLAGS+1] & RBBIDataWrapper.RBBI_BOF_REQUIRED) != 0) {\r
1182             category = 2;\r
1183             mode     = RBBI_START;\r
1184         }\r
1185         \r
1186         if (fTrace) {\r
1187             System.out.println("Handle Prev   pos   char  state category ");\r
1188         }\r
1189         \r
1190         // loop until we reach the beginning of the text or transition to state 0\r
1191         //\r
1192         mainLoop: for (;;) {\r
1193             innerBlock: {\r
1194                 if (c == CI_DONE32) {\r
1195                     // Reached end of input string.\r
1196                     if (mode == RBBI_END || fRData.fHeader.fVersion == 1) {\r
1197                         // Either this is the old (ICU 3.2 and earlier) format data which\r
1198                         // does not support explicit support for matching {eof}, or\r
1199                         // we have already done the {eof} iteration.  Now is the time\r
1200                         // to unconditionally bail out.\r
1201                         if (lookaheadResult < result) {\r
1202                             // We ran off the end of the string with a pending look-ahead match.\r
1203                             // Treat this as if the look-ahead condition had been met, and return\r
1204                             //  the match at the / position from the look-ahead rule.\r
1205                             result = lookaheadResult;\r
1206                             lookaheadStatus = 0;\r
1207                         } else if (result == initialPosition) {\r
1208                             // Ran off start, no match found.\r
1209                             // Move one position (towards the start, since we are doing previous.)\r
1210                             fText.setIndex(initialPosition);\r
1211                             CIPrevious32(fText);\r
1212                         }\r
1213                         break mainLoop;\r
1214                     }\r
1215                     mode = RBBI_END;\r
1216                     category = 1;\r
1217                 }\r
1218                 \r
1219                 if (mode == RBBI_RUN) {\r
1220                     // look up the current character's category, which tells us\r
1221                     // which column in the state table to look at.\r
1222                     //\r
1223                     category = (short) fRData.fTrie.getCodePointValue(c);\r
1224                     \r
1225                     // Check the dictionary bit in the character's category.\r
1226                     //    Counter is only used by dictionary based iterators (subclasses).\r
1227                     //    Chars that need to be handled by a dictionary have a flag bit set\r
1228                     //    in their category values.\r
1229                     //\r
1230                     if ((category & 0x4000) != 0)  {\r
1231                         fDictionaryCharCount++;\r
1232                         //  And off the dictionary flag bit.\r
1233                         category &= ~0x4000;\r
1234                     }\r
1235                 }\r
1236                 \r
1237                 \r
1238                 if (fTrace) {\r
1239                     System.out.print("             " + fText.getIndex() + "   ");\r
1240                     if (0x20 <= c && c < 0x7f) {\r
1241                         System.out.print("  " + c + "  ");\r
1242                     } else {\r
1243                         System.out.print(" " + Integer.toHexString(c) + " ");\r
1244                     }\r
1245                     System.out.println(" " + state + "  " + category + " ");\r
1246                 }\r
1247                 \r
1248                 // State Transition - move machine to its next state\r
1249                 //\r
1250                 state = stateTable[row + RBBIDataWrapper.NEXTSTATES + category];\r
1251                 row = fRData.getRowIndex(state);\r
1252                 \r
1253                 if (stateTable[row + RBBIDataWrapper.ACCEPTING] == -1) {\r
1254                     // Match found, common case, could have lookahead so we move\r
1255                     // on to check it\r
1256                     result = fText.getIndex();\r
1257                 }\r
1258                 \r
1259                 if (stateTable[row + RBBIDataWrapper.LOOKAHEAD] != 0) {\r
1260                     if (lookaheadStatus != 0\r
1261                             && stateTable[row + RBBIDataWrapper.ACCEPTING] == lookaheadStatus) {\r
1262                         // Lookahead match is completed. Set the result\r
1263                         // accordingly, but only\r
1264                         // if no other rule has matched further in the mean\r
1265                         // time.\r
1266                         result = lookaheadResult;\r
1267                         lookaheadStatus = 0;\r
1268                         // TODO: make a standalone hard break in a rule work.\r
1269                         \r
1270                         if (lookAheadHardBreak) {\r
1271                             break mainLoop;\r
1272                         }\r
1273                         // Look-ahead completed, but other rules may match further.\r
1274                         // Continue on.\r
1275                         // TODO: junk this feature?  I don't think that it's used anywhere.\r
1276                         break innerBlock;\r
1277                     }\r
1278                     // Hit a possible look-ahead match. We are at the\r
1279                     // position of the '/'. Remember this position.\r
1280                     lookaheadResult = fText.getIndex();\r
1281                     lookaheadStatus = stateTable[row + RBBIDataWrapper.LOOKAHEAD];\r
1282                     break innerBlock;\r
1283                 } \r
1284                 \r
1285                 // not lookahead...\r
1286                 if (stateTable[row + RBBIDataWrapper.ACCEPTING] != 0) {\r
1287                     // This is a plain (non-look-ahead) accepting state.\r
1288                     if (!lookAheadHardBreak) {\r
1289                         // Clear out any pending look-ahead matches,\r
1290                         // but only if not doing the lookAheadHardBreak option\r
1291                         // which needs to force a break no matter what is going\r
1292                         // on with the rest of the match, i.e. we can't abandon\r
1293                         // a partially completed look-ahead match because\r
1294                         // some other rule matched further than the '/' position\r
1295                         // in the look-ahead match.\r
1296                         lookaheadStatus = 0; \r
1297                     }\r
1298                 }\r
1299                 \r
1300             } // end of innerBlock.  "break innerBlock" in above code comes out here.\r
1301         \r
1302         \r
1303             if (state == STOP_STATE) {\r
1304                 // Normal loop exit is here\r
1305                 break mainLoop;\r
1306             }\r
1307         \r
1308             // then move iterator position backwards one character\r
1309             //\r
1310             if (mode == RBBI_RUN) {\r
1311                 c = CIPrevious32(fText);\r
1312             } else {\r
1313                 if (mode == RBBI_START) {\r
1314                     mode = RBBI_RUN;\r
1315                 }\r
1316             }\r
1317         \r
1318         \r
1319         }   // End of the main loop.\r
1320         \r
1321         // The state machine is done.  Check whether it found a match...\r
1322         //\r
1323         // If the iterator failed to advance in the match engine, force it ahead by one.\r
1324         //   (This really indicates a defect in the break rules.  They should always match\r
1325         //    at least one character.)\r
1326         if (result == initialPosition) {\r
1327             result = fText.setIndex(initialPosition);\r
1328             CIPrevious32(fText);\r
1329             result = fText.getIndex();\r
1330         }\r
1331         \r
1332         fText.setIndex(result);\r
1333         if (fTrace) {\r
1334             System.out.println("Result = " + result);\r
1335         }\r
1336         \r
1337         return result;\r
1338     }\r
1339 \r
1340 \r
1341 \r
1342 \r
1343 \r
1344     //-------------------------------------------------------------------------------\r
1345     \r
1346     //\r
1347     \r
1348     //  isDictionaryChar      Return true if the category lookup for this char\r
1349     \r
1350     //                        indicates that it is in the set of dictionary lookup\r
1351     \r
1352     //                        chars.\r
1353     \r
1354     //\r
1355     \r
1356     //                        This function is intended for use by dictionary based\r
1357     \r
1358     //                        break iterators.\r
1359     \r
1360     //\r
1361     \r
1362     //-------------------------------------------------------------------------------\r
1363     \r
1364     boolean isDictionaryChar(int c) {\r
1365     \r
1366         short  category = (short) fRData.fTrie.getCodePointValue(c);\r
1367     \r
1368         return (category & 0x4000) != 0;\r
1369     \r
1370     }\r
1371 \r
1372 }\r
1373 //eof\r