1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2001-2011, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.text; 10 import com.ibm.icu.impl.Utility; 11 12 class Quantifier implements UnicodeMatcher { 13 14 private UnicodeMatcher matcher; 15 16 private int minCount; 17 18 private int maxCount; 19 20 /** 21 * Maximum count a quantifier can have. 22 */ 23 public static final int MAX = Integer.MAX_VALUE; 24 25 public Quantifier(UnicodeMatcher theMatcher, 26 int theMinCount, int theMaxCount) { 27 if (theMatcher == null || theMinCount < 0 || theMaxCount < 0 || theMinCount > theMaxCount) { 28 throw new IllegalArgumentException(); 29 } 30 matcher = theMatcher; 31 minCount = theMinCount; 32 maxCount = theMaxCount; 33 } 34 35 /** 36 * Implement UnicodeMatcher API. 37 */ 38 public int matches(Replaceable text, 39 int[] offset, 40 int limit, 41 boolean incremental) { 42 int start = offset[0]; 43 int count = 0; 44 while (count < maxCount) { 45 int pos = offset[0]; 46 int m = matcher.matches(text, offset, limit, incremental); 47 if (m == U_MATCH) { 48 ++count; 49 if (pos == offset[0]) { 50 // If offset has not moved we have a zero-width match. 51 // Don't keep matching it infinitely. 52 break; 53 } 54 } else if (incremental && m == U_PARTIAL_MATCH) { 55 return U_PARTIAL_MATCH; 56 } else { 57 break; 58 } 59 } 60 if (incremental && offset[0] == limit) { 61 return U_PARTIAL_MATCH; 62 } 63 if (count >= minCount) { 64 return U_MATCH; 65 } 66 offset[0] = start; 67 return U_MISMATCH; 68 } 69 70 /** 71 * Implement UnicodeMatcher API 72 */ 73 public String toPattern(boolean escapeUnprintable) { 74 StringBuilder result = new StringBuilder(); 75 result.append(matcher.toPattern(escapeUnprintable)); 76 if (minCount == 0) { 77 if (maxCount == 1) { 78 return result.append('?').toString(); 79 } else if (maxCount == MAX) { 80 return result.append('*').toString(); 81 } 82 // else fall through 83 } else if (minCount == 1 && maxCount == MAX) { 84 return result.append('+').toString(); 85 } 86 result.append('{'); 87 result.append(Utility.hex(minCount,1)); 88 result.append(','); 89 if (maxCount != MAX) { 90 result.append(Utility.hex(maxCount,1)); 91 } 92 result.append('}'); 93 return result.toString(); 94 } 95 96 /** 97 * Implement UnicodeMatcher API 98 */ 99 public boolean matchesIndexValue(int v) { 100 return (minCount == 0) || matcher.matchesIndexValue(v); 101 } 102 103 /** 104 * Implementation of UnicodeMatcher API. Union the set of all 105 * characters that may be matched by this object into the given 106 * set. 107 * @param toUnionTo the set into which to union the source characters 108 * @returns a reference to toUnionTo 109 */ 110 public void addMatchSetTo(UnicodeSet toUnionTo) { 111 if (maxCount > 0) { 112 matcher.addMatchSetTo(toUnionTo); 113 } 114 } 115 } 116 117 //eof 118