ICU-8158 add plural rules support for getting unique keyword value

X-SVN-Rev: 29447
This commit is contained in:
Doug Felt 2011-02-16 19:43:24 +00:00
parent 9e2ef1c35b
commit c9bcfd3177
2 changed files with 108 additions and 22 deletions

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2010, International Business Machines Corporation and *
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -11,9 +11,10 @@ import java.io.Serializable;
import java.text.ParseException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import com.ibm.icu.impl.PluralRulesLoader;
@ -78,7 +79,7 @@ public class PluralRules implements Serializable {
private static final long serialVersionUID = 1;
private final RuleList rules;
private final Set<String> keywords;
private final Map<String, Double> keywords;
private int repeatLimit; // for equality test
// Standard keywords.
@ -150,6 +151,9 @@ public class PluralRules implements Serializable {
public int updateRepeatLimit(int limit) {
return limit;
}
public double uniqueValue() {
return Double.NaN;
}
};
/*
@ -173,6 +177,10 @@ public class PluralRules implements Serializable {
public int updateRepeatLimit(int limit) {
return limit;
}
public Double getKeywordValue() {
return Double.NaN;
}
};
@ -227,6 +235,11 @@ public class PluralRules implements Serializable {
*/
boolean isFulfilled(double n);
/*
* Returns the unique value that satisfies the constraint, or NaN.
*/
double uniqueValue();
/*
* Returns the larger of limit or the limit of this constraint.
* If the constraint is a simple range test, this is the higher
@ -248,6 +261,8 @@ public class PluralRules implements Serializable {
boolean appliesTo(double n);
/* Returns the larger of limit and this rule's limit. */
int updateRepeatLimit(int limit);
/* Returns the unique value that satisfies this rule, or NaN if there is no such value */
Double getKeywordValue();
}
/*
@ -258,7 +273,7 @@ public class PluralRules implements Serializable {
String select(double n);
/* Returns the set of defined keywords. */
Set<String> getKeywords();
Map<String, Double> getKeywords();
/* Return the value at which this rulelist starts repeating. */
int getRepeatLimit();
@ -491,6 +506,10 @@ public class PluralRules implements Serializable {
" integersOnly: " + integersOnly +
" low: " + lowerBound + " high: " + upperBound + "]";
}
public double uniqueValue() {
return mod == 0 && lowerBound == upperBound ? lowerBound : Double.NaN;
}
}
/* Convenience base class for and/or constraints. */
@ -524,6 +543,16 @@ public class PluralRules implements Serializable {
super(a, b, " && ");
}
public double uniqueValue() {
if (Double.isNaN(a.uniqueValue())) {
return b.uniqueValue();
}
if (Double.isNaN(b.uniqueValue())) {
return a.uniqueValue();
}
return a.uniqueValue() == b.uniqueValue() ? a.uniqueValue() : Double.NaN; // degenerate case
}
public boolean isFulfilled(double n) {
return a.isFulfilled(n) && b.isFulfilled(n);
}
@ -537,6 +566,10 @@ public class PluralRules implements Serializable {
super(a, b, " || ");
}
public double uniqueValue() {
return a.uniqueValue() == b.uniqueValue() ? (double)a.uniqueValue() : Double.NaN;
}
public boolean isFulfilled(double n) {
return a.isFulfilled(n) || b.isFulfilled(n);
}
@ -549,10 +582,12 @@ public class PluralRules implements Serializable {
private static class ConstrainedRule implements Rule, Serializable {
private static final long serialVersionUID = 1;
private final String keyword;
private final double keywordValue;
private final Constraint constraint;
public ConstrainedRule(String keyword, Constraint constraint) {
this.keyword = keyword;
this.keywordValue = constraint.uniqueValue();
this.constraint = constraint;
}
@ -581,6 +616,10 @@ public class PluralRules implements Serializable {
public String toString() {
return keyword + ": " + constraint;
}
public Double getKeywordValue() {
return keywordValue;
}
}
/*
@ -625,12 +664,12 @@ public class PluralRules implements Serializable {
return r.getKeyword();
}
public Set<String> getKeywords() {
Set<String> result = new HashSet<String>();
result.add(KEYWORD_OTHER);
public Map<String, Double> getKeywords() {
Map<String, Double> result = new HashMap<String, Double>();
result.put(KEYWORD_OTHER, Double.NaN);
RuleChain rc = this;
while (rc != null) {
result.add(rc.rule.getKeyword());
result.put(rc.rule.getKeyword(), rc.rule.getKeywordValue());
rc = rc.next;
}
return result;
@ -702,7 +741,7 @@ public class PluralRules implements Serializable {
*/
private PluralRules(RuleList rules) {
this.rules = rules;
this.keywords = Collections.unmodifiableSet(rules.getKeywords());
this.keywords = Collections.unmodifiableMap(rules.getKeywords());
}
/**
@ -725,7 +764,19 @@ public class PluralRules implements Serializable {
* @stable ICU 3.8
*/
public Set<String> getKeywords() {
return keywords;
return keywords.keySet();
}
/**
* Returns the unique value that this keyword matches, or NaN if the keyword matches
* multiple values or is not defined for this PluralRules.
*
* @param keyword the keyword to check for a unique value
* @return The unique value for the keyword, or NaN.
* @draft ICU 4.8
*/
public double getUniqueKeywordValue(String keyword) {
return keywords.containsKey(keyword) ? keywords.get(keyword) : Double.NaN;
}
/**
@ -736,7 +787,7 @@ public class PluralRules implements Serializable {
* @deprecated This API is ICU internal only.
*/
public Collection<Double> getSamples(String keyword, int max) {
if (!keywords.contains(keyword)) {
if (!keywords.containsKey(keyword)) {
return null;
}
LinkedHashSet<Double> results = new LinkedHashSet<Double>();
@ -833,8 +884,15 @@ public class PluralRules implements Serializable {
if (rhs == this) {
return true;
}
if (!rhs.getKeywords().equals(keywords)) {
return false;
if (!getKeywords().equals(rhs.getKeywords())) { // note, we're comparing keys only here
return false;
}
// can't compare maps for equality since values might include NaN and Nan != itself.
for (String k : getKeywords()) {
double val = getUniqueKeywordValue(k);
double rhsVal = rhs.getUniqueKeywordValue(k);
return Double.isNaN(val) ? Double.isNaN(rhsVal) : val == rhsVal;
}
int limit = Math.max(getRepeatLimit(), rhs.getRepeatLimit());

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2010, International Business Machines Corporation and *
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -213,10 +213,11 @@ public class PluralRulesTest extends TestFmwk {
* Tests the method public int hashCode()
*/
public void TestHashCode() {
PluralRules pr = PluralRules.DEFAULT;
if (106069776 != pr.hashCode()) {
errln("PluralRules.hashCode() was suppose to return 106069776 " + "when PluralRules.DEFAULT.");
}
// Bad test, breaks whenever PluralRules implementation changes.
// PluralRules pr = PluralRules.DEFAULT;
// if (106069776 != pr.hashCode()) {
// errln("PluralRules.hashCode() was suppose to return 106069776 " + "when PluralRules.DEFAULT.");
// }
}
/*
@ -225,9 +226,36 @@ public class PluralRulesTest extends TestFmwk {
public void TestEquals() {
PluralRules pr = PluralRules.DEFAULT;
// Tests when if (rhs == null) is true
if (pr.equals((PluralRules) null)) {
errln("PluralRules.equals(PluralRules) was suppose to return false " + "when passing null.");
errln("PluralRules.equals(PluralRules) was supposed to return false " + "when passing null.");
}
}
private void assertRuleValue(String rule, double value) {
assertRuleKeyValue("a:" + rule, "a", value);
}
private void assertRuleKeyValue(String rule, String key, double value) {
PluralRules pr = PluralRules.createRules(rule);
assertEquals(rule, value, pr.getUniqueKeywordValue(key));
}
/*
* Tests getUniqueKeywordValue()
*/
public void TestGetUniqueKeywordValue() {
assertRuleValue("n is 1", 1);
assertRuleValue("n in 2..2", 2);
assertRuleValue("n within 2..2", 2);
assertRuleValue("n in 3..4", Double.NaN);
assertRuleValue("n within 3..4", Double.NaN);
assertRuleValue("n is 2 or n is 2", 2);
assertRuleValue("n is 2 and n is 2", 2);
assertRuleValue("n is 2 or n is 3", Double.NaN);
assertRuleValue("n is 2 and n is 3", Double.NaN);
assertRuleValue("n is 2 or n in 2..3", Double.NaN);
assertRuleValue("n is 2 and n in 2..3", 2);
assertRuleKeyValue("a: n is 1", "not_defined", Double.NaN); // key not defined
assertRuleKeyValue("a: n is 1", "other", Double.NaN); // key matches default rule
}
}