1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2018 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 package ohos.global.icu.impl.number.parse; 5 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import ohos.global.icu.impl.StringSegment; 10 11 /** 12 * Composes a number of matchers, running one after another. Matches the input string only if all of the 13 * matchers in the series succeed. Performs greedy matches within the context of the series. 14 * 15 * @author sffc 16 * @hide exposed on OHOS 17 */ 18 public class SeriesMatcher implements NumberParseMatcher { 19 20 protected List<NumberParseMatcher> matchers = null; 21 protected boolean frozen = false; 22 addMatcher(NumberParseMatcher matcher)23 public void addMatcher(NumberParseMatcher matcher) { 24 assert !frozen; 25 if (matchers == null) { 26 matchers = new ArrayList<NumberParseMatcher>(); 27 } 28 matchers.add(matcher); 29 } 30 freeze()31 public void freeze() { 32 frozen = true; 33 } 34 length()35 public int length() { 36 return matchers == null ? 0 : matchers.size(); 37 } 38 39 @Override match(StringSegment segment, ParsedNumber result)40 public boolean match(StringSegment segment, ParsedNumber result) { 41 assert frozen; 42 if (matchers == null) { 43 return false; 44 } 45 46 // TODO: Give a nice way to reset ParsedNumber to avoid the copy here. 47 ParsedNumber backup = new ParsedNumber(); 48 backup.copyFrom(result); 49 50 int initialOffset = segment.getOffset(); 51 boolean maybeMore = true; 52 for (int i = 0; i < matchers.size();) { 53 NumberParseMatcher matcher = matchers.get(i); 54 int matcherOffset = segment.getOffset(); 55 if (segment.length() != 0) { 56 maybeMore = matcher.match(segment, result); 57 } else { 58 // Nothing for this matcher to match; ask for more. 59 maybeMore = true; 60 } 61 62 boolean success = (segment.getOffset() != matcherOffset); 63 boolean isFlexible = matcher instanceof NumberParseMatcher.Flexible; 64 if (success && isFlexible) { 65 // Match succeeded, and this is a flexible matcher. Re-run it. 66 } else if (success) { 67 // Match succeeded, and this is NOT a flexible matcher. Proceed to the next matcher. 68 i++; 69 // Small hack: if there is another matcher coming, do not accept trailing weak chars. 70 // Needed for proper handling of currency spacing. 71 if (i < matchers.size() && segment.getOffset() != result.charEnd && result.charEnd > matcherOffset) { 72 segment.setOffset(result.charEnd); 73 } 74 } else if (isFlexible) { 75 // Match failed, and this is a flexible matcher. Try again with the next matcher. 76 i++; 77 } else { 78 // Match failed, and this is NOT a flexible matcher. Exit. 79 segment.setOffset(initialOffset); 80 result.copyFrom(backup); 81 return maybeMore; 82 } 83 } 84 85 // All matchers in the series succeeded. 86 return maybeMore; 87 } 88 89 @Override smokeTest(StringSegment segment)90 public boolean smokeTest(StringSegment segment) { 91 assert frozen; 92 if (matchers == null) { 93 return false; 94 } 95 96 // SeriesMatchers are never allowed to start with a Flexible matcher. 97 assert !(matchers.get(0) instanceof NumberParseMatcher.Flexible); 98 return matchers.get(0).smokeTest(segment); 99 } 100 101 @Override postProcess(ParsedNumber result)102 public void postProcess(ParsedNumber result) { 103 assert frozen; 104 if (matchers == null) { 105 return; 106 } 107 108 for (int i = 0; i < matchers.size(); i++) { 109 NumberParseMatcher matcher = matchers.get(i); 110 matcher.postProcess(result); 111 } 112 } 113 114 @Override toString()115 public String toString() { 116 return "<SeriesMatcher " + matchers + ">"; 117 } 118 119 } 120