mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 06:53:45 +00:00
ICU-8474 fixes for serialization, which included change to equals
X-SVN-Rev: 33528
This commit is contained in:
parent
eea5fa79bb
commit
297e433797
9 changed files with 2878 additions and 449 deletions
|
@ -7,6 +7,11 @@
|
|||
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -303,7 +308,7 @@ public class PluralRules implements Serializable {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
|
||||
public int updateRepeatLimit(int limit) {
|
||||
|
@ -374,7 +379,7 @@ public class PluralRules implements Serializable {
|
|||
public static class NumberInfo implements Comparable<NumberInfo> {
|
||||
public final double source;
|
||||
public final int visibleFractionDigitCount;
|
||||
public final int fractionalDigits;
|
||||
public final long fractionalDigits;
|
||||
public final long intValue;
|
||||
public final boolean hasIntegerValue;
|
||||
|
||||
|
@ -384,6 +389,19 @@ public class PluralRules implements Serializable {
|
|||
fractionalDigits = f;
|
||||
intValue = (long)n;
|
||||
hasIntegerValue = source == intValue;
|
||||
// check values. TODO make into unit test.
|
||||
//
|
||||
// long visiblePower = (int) Math.pow(10, v);
|
||||
// if (fractionalDigits > visiblePower) {
|
||||
// throw new IllegalArgumentException();
|
||||
// }
|
||||
// double fraction = intValue + (fractionalDigits / (double) visiblePower);
|
||||
// if (fraction != source) {
|
||||
// double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source));
|
||||
// if (diff > 0.00000001d) {
|
||||
// throw new IllegalArgumentException();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// Ugly, but for samples we don't care.
|
||||
|
@ -391,17 +409,6 @@ public class PluralRules implements Serializable {
|
|||
this(n,v,getFractionalDigits(n, v));
|
||||
}
|
||||
|
||||
// Ugly, but for samples we don't care.
|
||||
public static int decimals(double n) {
|
||||
String temp = String.valueOf(n);
|
||||
return temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1;
|
||||
}
|
||||
|
||||
// Ugly, but for samples we don't care.
|
||||
public NumberInfo (String n) {
|
||||
this(Double.parseDouble(n), getVisibleFractionCount(n));
|
||||
}
|
||||
|
||||
private static int getFractionalDigits(double n, int v) {
|
||||
if (v == 0) {
|
||||
return 0;
|
||||
|
@ -412,23 +419,35 @@ public class PluralRules implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private static int getVisibleFractionCount(String value) {
|
||||
int decimalPos = value.trim().indexOf('.') + 1;
|
||||
if (decimalPos == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return value.length() - decimalPos - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public NumberInfo(double n) {
|
||||
this(n, decimals(n));
|
||||
}
|
||||
|
||||
// Ugly, but for samples we don't care.
|
||||
public static int decimals(double n) {
|
||||
String temp = String.valueOf(n);
|
||||
return temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1;
|
||||
}
|
||||
|
||||
public NumberInfo(long n) {
|
||||
this(n,0);
|
||||
}
|
||||
|
||||
// Ugly, but for samples we don't care.
|
||||
public NumberInfo (String n) {
|
||||
this(Double.parseDouble(n), getVisibleFractionCount(n));
|
||||
}
|
||||
|
||||
private static int getVisibleFractionCount(String value) {
|
||||
value = value.trim();
|
||||
int decimalPos = value.indexOf('.') + 1;
|
||||
if (decimalPos == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return value.length() - decimalPos;
|
||||
}
|
||||
}
|
||||
|
||||
public double get(Operand operand) {
|
||||
switch(operand) {
|
||||
default: return source;
|
||||
|
@ -446,13 +465,20 @@ public class PluralRules implements Serializable {
|
|||
* We're not going to care about NaN.
|
||||
*/
|
||||
public int compareTo(NumberInfo other) {
|
||||
if (intValue != other.intValue) {
|
||||
return intValue < other.intValue ? -1 : 1;
|
||||
}
|
||||
if (source != other.source) {
|
||||
return source < other.source ? -1 : 1;
|
||||
}
|
||||
if (visibleFractionDigitCount != other.visibleFractionDigitCount) {
|
||||
return visibleFractionDigitCount < other.visibleFractionDigitCount ? -1 : 1;
|
||||
}
|
||||
return fractionalDigits - other.fractionalDigits;
|
||||
long diff = fractionalDigits - other.fractionalDigits;
|
||||
if (diff != 0) {
|
||||
return diff < 0 ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object arg0) {
|
||||
|
@ -471,7 +497,7 @@ public class PluralRules implements Serializable {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
// TODO Auto-generated method stub
|
||||
return fractionalDigits + 37 * (visibleFractionDigitCount + (int)(37 * source));
|
||||
return (int)(fractionalDigits + 37 * (visibleFractionDigitCount + (int)(37 * source)));
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -660,13 +686,13 @@ public class PluralRules implements Serializable {
|
|||
String[] pair = Utility.splitString(range, "..");
|
||||
double low, high;
|
||||
if (pair.length == 2) {
|
||||
low = Long.parseLong(pair[0]);
|
||||
high = Long.parseLong(pair[1]);
|
||||
low = Double.parseDouble(pair[0]);
|
||||
high = Double.parseDouble(pair[1]);
|
||||
if (low > high) {
|
||||
throw unexpected(range, condition);
|
||||
}
|
||||
} else if (pair.length == 1) {
|
||||
low = high = Long.parseLong(pair[0]);
|
||||
low = high = Double.parseDouble(pair[0]);
|
||||
} else {
|
||||
throw unexpected(range, condition);
|
||||
}
|
||||
|
@ -679,7 +705,7 @@ public class PluralRules implements Serializable {
|
|||
vals = null;
|
||||
}
|
||||
} else {
|
||||
lowBound = highBound = Long.parseLong(t);
|
||||
lowBound = highBound = Double.parseDouble(t);
|
||||
}
|
||||
|
||||
if (x != tokens.length) {
|
||||
|
@ -761,6 +787,10 @@ public class PluralRules implements Serializable {
|
|||
private static RuleList parseRuleChain(String description)
|
||||
throws ParseException {
|
||||
RuleList result = new RuleList();
|
||||
// remove trailing ;
|
||||
if (description.endsWith(";")) {
|
||||
description = description.substring(0,description.length()-1);
|
||||
}
|
||||
String[] rules = Utility.split(description, ';');
|
||||
for (int i = 0; i < rules.length; ++i) {
|
||||
result.addRule(parseRule(rules[i].trim()));
|
||||
|
@ -808,30 +838,30 @@ public class PluralRules implements Serializable {
|
|||
if (upperBound != lowerBound) {
|
||||
toAddTo.add(new NumberInfo(upperBound + offset));
|
||||
}
|
||||
// if (range_list != null) {
|
||||
// // add from each range
|
||||
// for (int i = 0; i < range_list.length; i += 2) {
|
||||
// double lower = range_list[i];
|
||||
// double upper = range_list[i+1];
|
||||
// if (lower != lowerBound) {
|
||||
// toAddTo.add(new NumberInfo(lower + offset));
|
||||
// }
|
||||
// if (upper != upperBound) {
|
||||
// toAddTo.add(new NumberInfo(upper + offset));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (range_list != null) {
|
||||
// // add from each range
|
||||
// for (int i = 0; i < range_list.length; i += 2) {
|
||||
// double lower = range_list[i];
|
||||
// double upper = range_list[i+1];
|
||||
// if (lower != lowerBound) {
|
||||
// toAddTo.add(new NumberInfo(lower + offset));
|
||||
// }
|
||||
// if (upper != upperBound) {
|
||||
// toAddTo.add(new NumberInfo(upper + offset));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (!integersOnly) {
|
||||
double average = (lowerBound + upperBound) / 2.0d;
|
||||
toAddTo.add(new NumberInfo(average + offset));
|
||||
// if (range_list != null) {
|
||||
// // we will just add one value from the middle
|
||||
// for (int i = 0; i < range_list.length; i += 2) {
|
||||
// double lower = range_list[i];
|
||||
// double upper = range_list[i+1];
|
||||
// toAddTo.add(new NumberInfo((lower + upper) / 2.0d + offset));
|
||||
// }
|
||||
// }
|
||||
// if (range_list != null) {
|
||||
// // we will just add one value from the middle
|
||||
// for (int i = 0; i < range_list.length; i += 2) {
|
||||
// double lower = range_list[i];
|
||||
// double upper = range_list[i+1];
|
||||
// toAddTo.add(new NumberInfo((lower + upper) / 2.0d + offset));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1095,6 +1125,9 @@ public class PluralRules implements Serializable {
|
|||
Map<String, String> ordered = new TreeMap<String, String>(KEYWORD_COMPARATOR);
|
||||
for (Rule rule : rules) {
|
||||
String keyword = rule.getKeyword();
|
||||
if (keyword.equals("other")) {
|
||||
continue;
|
||||
}
|
||||
String constraint = rule.getConstraint();
|
||||
ordered.put(keyword, constraint);
|
||||
}
|
||||
|
@ -1145,8 +1178,10 @@ public class PluralRules implements Serializable {
|
|||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
static final int[] TENS = {1, 10, 100, 1000};
|
||||
|
||||
private static final int[] TENS = {1, 10, 100, 1000, 10000, 100000, 1000000};
|
||||
|
||||
private static final int LIMIT_FRACTION_SAMPLES = 3;
|
||||
|
||||
private Set<NumberInfo> fractions(Set<NumberInfo> original) {
|
||||
Set<NumberInfo> toAddTo = new HashSet<NumberInfo>();
|
||||
|
@ -1156,25 +1191,52 @@ public class PluralRules implements Serializable {
|
|||
result.add((int)base1.intValue);
|
||||
}
|
||||
List<Integer> ints = new ArrayList<Integer>(result);
|
||||
Set<String> keywords = new HashSet<String>();
|
||||
|
||||
for (int j = 0; j < ints.size(); ++j) {
|
||||
Integer base = ints.get(j);
|
||||
Integer fract = ints.get((j == 0 ? ints.size() : j) -1);
|
||||
for (int visibleFractions = 1; visibleFractions < 3; ++visibleFractions) {
|
||||
for (int i = 1; i <= visibleFractions; ++i) {
|
||||
// with visible fractions = 3, and fract = 1, then we should get x.10, 0.01
|
||||
// with visible fractions = 3, and fract = 15, then we should get x.15, x.15
|
||||
if (fract >= TENS[i]) {
|
||||
continue;
|
||||
String keyword = select(base);
|
||||
if (keywords.contains(keyword)) {
|
||||
continue;
|
||||
}
|
||||
keywords.add(keyword);
|
||||
toAddTo.add(new NumberInfo(base,1)); // add .0
|
||||
toAddTo.add(new NumberInfo(base,2)); // add .00
|
||||
Integer fract = getDifferentCategory(ints, keyword);
|
||||
if (fract >= TENS[LIMIT_FRACTION_SAMPLES-1]) { // make sure that we always get the value
|
||||
toAddTo.add(new NumberInfo(base + "." + fract));
|
||||
} else {
|
||||
for (int visibleFractions = 1; visibleFractions < LIMIT_FRACTION_SAMPLES; ++visibleFractions) {
|
||||
for (int i = 1; i <= visibleFractions; ++i) {
|
||||
// with visible fractions = 3, and fract = 1, then we should get x.10, 0.01
|
||||
// with visible fractions = 3, and fract = 15, then we should get x.15, x.15
|
||||
if (fract >= TENS[i]) {
|
||||
continue;
|
||||
}
|
||||
toAddTo.add(new NumberInfo(base + fract/(double)TENS[i], visibleFractions));
|
||||
}
|
||||
NumberInfo combo = new NumberInfo(base + fract/(double)TENS[i], visibleFractions);
|
||||
toAddTo.add(combo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return toAddTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ints
|
||||
* @param base
|
||||
* @return
|
||||
*/
|
||||
private Integer getDifferentCategory(List<Integer> ints, String keyword) {
|
||||
for (int i = ints.size() - 1; i >= 0; --i) {
|
||||
Integer other = ints.get(i);
|
||||
String keywordOther = select(other);
|
||||
if (!keywordOther.equals(keyword)) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
return 37;
|
||||
}
|
||||
|
||||
private boolean addConditional(Set<NumberInfo> toAddTo, Set<NumberInfo> others, double trial) {
|
||||
boolean added;
|
||||
NumberInfo toAdd = new NumberInfo(trial);
|
||||
|
@ -1307,7 +1369,7 @@ public class PluralRules implements Serializable {
|
|||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
public String select(NumberInfo sample) {
|
||||
return rules.select(new NumberInfo(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits));
|
||||
return rules.select(sample);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1472,65 +1534,67 @@ public class PluralRules implements Serializable {
|
|||
addRelation(foundKeywords, keyword, s);
|
||||
}
|
||||
main:
|
||||
if (foundKeywords.size() != keywords.size()) {
|
||||
for (int i = 1; i < 1000; ++i) {
|
||||
boolean done = addIfNotPresent(i, mentioned, foundKeywords);
|
||||
if (done) break main;
|
||||
if (foundKeywords.size() != keywords.size()) {
|
||||
for (int i = 1; i < 1000; ++i) {
|
||||
boolean done = addIfNotPresent(i, mentioned, foundKeywords);
|
||||
if (done) break main;
|
||||
}
|
||||
// if we are not done, try tenths
|
||||
for (int i = 10; i < 1000; ++i) {
|
||||
boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords);
|
||||
if (done) break main;
|
||||
}
|
||||
System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + rules + "\n\t" + mentioned);
|
||||
}
|
||||
// if we are not done, try tenths
|
||||
for (int i = 10; i < 1000; ++i) {
|
||||
boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords);
|
||||
if (done) break main;
|
||||
}
|
||||
System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + rules + "\n\t" + mentioned);
|
||||
}
|
||||
mentioned.add(new NumberInfo(0)); // always there
|
||||
mentioned.add(new NumberInfo(1)); // always there
|
||||
mentioned.add(new NumberInfo(2)); // always there
|
||||
mentioned.add(new NumberInfo(0.1,1)); // always there
|
||||
mentioned.add(new NumberInfo(1.99,2)); // always there
|
||||
mentioned.addAll(fractions(mentioned));
|
||||
// Set<NumberInfo> toAddTo = mentioned;
|
||||
// {
|
||||
// // once done, manufacture values for the OTHER case
|
||||
// int otherCount = 2;
|
||||
// for (int i = 0; i < 1000; ++i) {
|
||||
// }
|
||||
// NumberInfo last = null;
|
||||
// Set<NumberInfo> others = new LinkedHashSet<NumberInfo>();
|
||||
// for (NumberInfo s : toAddTo) {
|
||||
// double trial;
|
||||
// if (last == null) {
|
||||
// trial = s.source-0.5;
|
||||
// } else {
|
||||
// double diff = s.source - last.source;
|
||||
// if (diff > 1.0d) {
|
||||
// trial = Math.floor(s.source);
|
||||
// if (trial == s.source) {
|
||||
// --trial;
|
||||
// }
|
||||
// } else {
|
||||
// trial = (s.source + last.source) / 2;
|
||||
// }
|
||||
// }
|
||||
// if (trial >= 0) {
|
||||
// addConditional(toAddTo, others, trial);
|
||||
// }
|
||||
// last = s;
|
||||
// }
|
||||
// double trial = last == null ? 0 : last.source;
|
||||
// double fraction = 0;
|
||||
// while (otherCount > 0) {
|
||||
// if (addConditional(toAddTo, others, trial = trial * 2 + 1 + fraction)) {
|
||||
// --otherCount;
|
||||
// }
|
||||
// fraction += 0.125;
|
||||
// }
|
||||
// toAddTo.addAll(others);
|
||||
// others.clear();
|
||||
// toAddTo.addAll(fractions(toAddTo, others));
|
||||
//
|
||||
// }
|
||||
// Set<NumberInfo> toAddTo = mentioned;
|
||||
// {
|
||||
// // once done, manufacture values for the OTHER case
|
||||
// int otherCount = 2;
|
||||
// for (int i = 0; i < 1000; ++i) {
|
||||
// }
|
||||
// NumberInfo last = null;
|
||||
// Set<NumberInfo> others = new LinkedHashSet<NumberInfo>();
|
||||
// for (NumberInfo s : toAddTo) {
|
||||
// double trial;
|
||||
// if (last == null) {
|
||||
// trial = s.source-0.5;
|
||||
// } else {
|
||||
// double diff = s.source - last.source;
|
||||
// if (diff > 1.0d) {
|
||||
// trial = Math.floor(s.source);
|
||||
// if (trial == s.source) {
|
||||
// --trial;
|
||||
// }
|
||||
// } else {
|
||||
// trial = (s.source + last.source) / 2;
|
||||
// }
|
||||
// }
|
||||
// if (trial >= 0) {
|
||||
// addConditional(toAddTo, others, trial);
|
||||
// }
|
||||
// last = s;
|
||||
// }
|
||||
// double trial = last == null ? 0 : last.source;
|
||||
// double fraction = 0;
|
||||
// while (otherCount > 0) {
|
||||
// if (addConditional(toAddTo, others, trial = trial * 2 + 1 + fraction)) {
|
||||
// --otherCount;
|
||||
// }
|
||||
// fraction += 0.125;
|
||||
// }
|
||||
// toAddTo.addAll(others);
|
||||
// others.clear();
|
||||
// toAddTo.addAll(fractions(toAddTo, others));
|
||||
//
|
||||
// }
|
||||
for (NumberInfo s : mentioned) {
|
||||
String keyword = select(s.source, s.visibleFractionDigitCount, s.fractionalDigits);
|
||||
String keyword = select(s);
|
||||
Set<NumberInfo> list = sampleFractionMap.get(keyword);
|
||||
if (list == null) {
|
||||
list = new LinkedHashSet<NumberInfo>(); // will be sorted because the iteration is
|
||||
|
@ -1675,12 +1739,21 @@ public class PluralRules implements Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
int limit = Math.max(getRepeatLimit(), rhs.getRepeatLimit());
|
||||
for (int i = 0; i < limit * 2; ++i) {
|
||||
if (!select(i).equals(rhs.select(i))) {
|
||||
return false;
|
||||
for (String keyword : rhs.getKeywords()) {
|
||||
String rules2 = getRules(keyword);
|
||||
String rules3 = rhs.getRules(keyword);
|
||||
if (rules2 != rules3) {
|
||||
if (rules2 == null || !rules2.equals(rules3)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// int limit = Math.max(getRepeatLimit(), rhs.getRepeatLimit());
|
||||
// for (int i = 0; i < limit * 2; ++i) {
|
||||
// if (!select(i).equals(rhs.select(i))) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1807,4 +1880,21 @@ public class PluralRules implements Serializable {
|
|||
public String getRules(String keyword) {
|
||||
return rules.getRules(keyword);
|
||||
}
|
||||
|
||||
private void writeObject(
|
||||
ObjectOutputStream out)
|
||||
throws IOException {
|
||||
throw new NotSerializableException();
|
||||
}
|
||||
private void readObject(ObjectInputStream in
|
||||
) throws IOException, ClassNotFoundException {
|
||||
throw new NotSerializableException();
|
||||
}
|
||||
private void readObjectNoData(
|
||||
) throws ObjectStreamException {
|
||||
throw new NotSerializableException();
|
||||
}
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new PluralRulesSerialProxy(toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, Google Inc, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author markdavis
|
||||
*
|
||||
*/
|
||||
public class PluralRulesSerialProxy implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
private final String data;
|
||||
PluralRulesSerialProxy(String rules) {
|
||||
data = rules;
|
||||
}
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return PluralRules.createRules(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,29 +65,45 @@ public abstract class PluralRulesFactory {
|
|||
static Relation<ULocale,NumberInfo> EXTRA_SAMPLES = Relation.of(new HashMap<ULocale,Set<NumberInfo>>(), HashSet.class);
|
||||
static {
|
||||
String[][] overrides = {
|
||||
{"bn", ""},
|
||||
{"en,ca,de,et,fi,gl,it,nl,pt,sv,sw,ta,te,ur", "one: j is 1"},
|
||||
{"cs,sk", "one: j is 1; few: j in 2..4; many: v is not 0"},
|
||||
{"cy", "one: n is 1; two: n is 2; few: n is 3; many: n is 6"},
|
||||
//{"el", "one: j is 1 or i is 0 and f is 1"},
|
||||
{"da,is", "one: j is 1 or f is 1"},
|
||||
{"fil", "one: j in 0..1"},
|
||||
{"he", "one: j is 1; two: j is 2", "10,20"},
|
||||
{"hi", "one: n within 0..1"},
|
||||
{"hr", "one: j mod 10 is 1 and j mod 100 is not 11; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"},
|
||||
{"hy", "one: n within 0..2 and n is not 2"},
|
||||
// {"hr", "one: j mod 10 is 1 and j mod 100 is not 11; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"},
|
||||
{"lv", "zero: n mod 10 is 0" +
|
||||
" or n mod 10 in 11..19" +
|
||||
" or v in 1..6 and f is not 0 and f mod 10 is 0" +
|
||||
" or v in 1..6 and f mod 10 in 11..19;" +
|
||||
"one: n mod 10 is 1 and n mod 100 is not 11" +
|
||||
" or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" +
|
||||
" or v not in 0..6 and f mod 10 is 1"},
|
||||
" or v not in 0..6 and f mod 10 is 1"},
|
||||
// {"lv", "zero: n mod 10 is 0" +
|
||||
// " or n mod 10 in 11..19" +
|
||||
// " or v in 1..6 and f is not 0 and f mod 10 is 0" +
|
||||
// " or v in 1..6 and f mod 10 in 11..19;" +
|
||||
// "one: n mod 10 is 1 and n mod 100 is not 11" +
|
||||
// " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" +
|
||||
// " or v not in 0..6 and f mod 10 is 1"},
|
||||
{"pl", "one: j is 1; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j is not 1 and j mod 10 in 0..1 or j mod 10 in 5..9 or j mod 100 in 12..14"},
|
||||
{"sl", "one: j mod 100 is 1; two: j mod 100 is 2; few: j mod 100 in 3..4 or v is not 0"},
|
||||
{"sr", "one: j mod 10 is 1 and j mod 100 is not 11" +
|
||||
" or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" +
|
||||
" or v not in 0..6 and f mod 10 is 1;" +
|
||||
// {"sr", "one: j mod 10 is 1 and j mod 100 is not 11" +
|
||||
// " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" +
|
||||
// " or v not in 0..6 and f mod 10 is 1;" +
|
||||
// "few: j mod 10 in 2..4 and j mod 100 not in 12..14" +
|
||||
// " or v in 1..6 and f mod 10 in 2..4 and f mod 100 not in 12..14" +
|
||||
// " or v not in 0..6 and f mod 10 in 2..4"
|
||||
// },
|
||||
{"sr,hr", "one: j mod 10 is 1 and j mod 100 is not 11" +
|
||||
" or f mod 10 is 1 and f mod 100 is not 11;" +
|
||||
"few: j mod 10 in 2..4 and j mod 100 not in 12..14" +
|
||||
" or v in 1..6 and f mod 10 in 2..4 and f mod 100 not in 12..14" +
|
||||
" or v not in 0..6 and f mod 10 in 2..4"
|
||||
" or f mod 10 in 2..4 and f mod 100 not in 12..14"
|
||||
},
|
||||
// +
|
||||
// " ; many: j mod 10 is 0 " +
|
||||
// " or j mod 10 in 5..9 " +
|
||||
|
@ -96,11 +112,14 @@ public abstract class PluralRulesFactory {
|
|||
// " or v in 1..6 and f mod 10 in 5..9" +
|
||||
// " or v in 1..6 and f mod 100 in 11..14" +
|
||||
// " or v not in 0..6 and f mod 10 in 5..9"
|
||||
},
|
||||
{"ro", "one: j is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"},
|
||||
{"ru,uk", "one: j mod 10 is 1 and j mod 100 is not 11;" +
|
||||
" few: j mod 10 in 2..4 and j mod 100 not in 12..14;" +
|
||||
" many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"},
|
||||
{"ru", "one: j mod 10 is 1 and j mod 100 is not 11;" +
|
||||
" many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"
|
||||
// + "; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"
|
||||
},
|
||||
{"uk", "one: j mod 10 is 1 and j mod 100 is not 11; " +
|
||||
"few: j mod 10 in 2..4 and j mod 100 not in 12..14; " +
|
||||
"many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"},
|
||||
};
|
||||
for (String[] pair : overrides) {
|
||||
for (String locale : pair[0].split("\\s*,\\s*")) {
|
||||
|
@ -160,4 +179,79 @@ public abstract class PluralRulesFactory {
|
|||
return result == null ? ULocale.ROOT : result;
|
||||
}
|
||||
};
|
||||
|
||||
static String[][] OLDRULES = {
|
||||
{"af", "one: n is 1"},
|
||||
{"am", "one: n in 0..1"},
|
||||
{"ar", "zero: n is 0; one: n is 1; two: n is 2; few: n mod 100 in 3..10; many: n mod 100 in 11..99"},
|
||||
{"az", "other: null"},
|
||||
{"bg", "one: n is 1"},
|
||||
{"bn", "one: n is 1"},
|
||||
{"ca", "one: n is 1"},
|
||||
{"cs", "one: n is 1; few: n in 2..4"},
|
||||
{"cy", "zero: n is 0; one: n is 1; two: n is 2; few: n is 3; many: n is 6"},
|
||||
{"da", "one: n is 1"},
|
||||
{"de", "one: n is 1"},
|
||||
{"el", "one: n is 1"},
|
||||
{"en", "one: n is 1"},
|
||||
{"es", "one: n is 1"},
|
||||
{"et", "one: n is 1"},
|
||||
{"eu", "one: n is 1"},
|
||||
{"fa", "other: null"},
|
||||
{"fi", "one: n is 1"},
|
||||
{"fil", "one: n in 0..1"},
|
||||
{"fr", "one: n within 0..2 and n is not 2"},
|
||||
{"gl", "one: n is 1"},
|
||||
{"gu", "one: n is 1"},
|
||||
{"hi", "one: n in 0..1"},
|
||||
{"hr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"hu", "other: null"},
|
||||
{"hy", "one: n is 1"},
|
||||
{"id", "other: null"},
|
||||
{"is", "one: n is 1"},
|
||||
{"it", "one: n is 1"},
|
||||
{"he", "one: n is 1; two: n is 2; many: n is not 0 and n mod 10 is 0"},
|
||||
{"ja", "other: null"},
|
||||
{"ka", "other: null"},
|
||||
{"kk", "one: n is 1"},
|
||||
{"km", "other: null"},
|
||||
{"kn", "other: null"},
|
||||
{"ko", "other: null"},
|
||||
{"ky", "one: n is 1"},
|
||||
{"lo", "other: null"},
|
||||
{"lt", "one: n mod 10 is 1 and n mod 100 not in 11..19; few: n mod 10 in 2..9 and n mod 100 not in 11..19"},
|
||||
{"lv", "zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11"},
|
||||
{"mk", "one: n mod 10 is 1 and n is not 11"},
|
||||
{"ml", "one: n is 1"},
|
||||
{"mn", "one: n is 1"},
|
||||
{"mr", "one: n is 1"},
|
||||
{"ms", "other: null"},
|
||||
{"my", "other: null"},
|
||||
{"ne", "one: n is 1"},
|
||||
{"nl", "one: n is 1"},
|
||||
{"nb", "one: n is 1"},
|
||||
{"pa", "one: n is 1"},
|
||||
{"pl", "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14"},
|
||||
{"ps", "one: n is 1"},
|
||||
{"pt", "one: n is 1"},
|
||||
{"ro", "one: n is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"},
|
||||
{"ru", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"si", "other: null"},
|
||||
{"sk", "one: n is 1; few: n in 2..4"},
|
||||
{"sl", "one: n mod 100 is 1; two: n mod 100 is 2; few: n mod 100 in 3..4"},
|
||||
{"sq", "one: n is 1"},
|
||||
{"sr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"sv", "one: n is 1"},
|
||||
{"sw", "one: n is 1"},
|
||||
{"ta", "one: n is 1"},
|
||||
{"te", "one: n is 1"},
|
||||
{"th", "other: null"},
|
||||
{"tr", "other: null"},
|
||||
{"uk", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"ur", "one: n is 1"},
|
||||
{"uz", "other: null"},
|
||||
{"vi", "other: null"},
|
||||
{"zh", "other: null"},
|
||||
{"zu", "one: n is 1"},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
*/
|
||||
package com.ibm.icu.dev.test.format;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -36,11 +42,11 @@ import com.ibm.icu.util.ULocale;
|
|||
* @author markdavis (Mark Davis) [for fractional support]
|
||||
*/
|
||||
public class PluralRulesTest extends TestFmwk {
|
||||
|
||||
|
||||
static boolean USE_ALT = System.getProperty("alt_plurals") != null;
|
||||
|
||||
|
||||
PluralRulesFactory factory = USE_ALT ? PluralRulesFactory.ALTERNATE : PluralRulesFactory.NORMAL;
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new PluralRulesTest().run(args);
|
||||
}
|
||||
|
@ -163,43 +169,43 @@ public class PluralRulesTest extends TestFmwk {
|
|||
|
||||
public void testUniqueRules() {
|
||||
main:
|
||||
for (ULocale locale : factory.getAvailableULocales()) {
|
||||
PluralRules rules = factory.forLocale(locale);
|
||||
Collection<NumberInfo> samples = rules.getFractionSamples();
|
||||
Map<String,PluralRules> keywordToRule = new HashMap<String,PluralRules>();
|
||||
for (String keyword : rules.getKeywords()) {
|
||||
if (keyword.equals("other")) {
|
||||
continue;
|
||||
}
|
||||
String rules2 = keyword + ":" + rules.getRules(keyword);
|
||||
PluralRules singleRule = PluralRules.createRules(rules2);
|
||||
if (singleRule == null) {
|
||||
errln("Can't generate single rule for " + rules2);
|
||||
PluralRules.createRules(rules2); // for debugging
|
||||
continue main;
|
||||
}
|
||||
keywordToRule.put(keyword, singleRule);
|
||||
}
|
||||
Map<NumberInfo, String> collisionTest = new TreeMap();
|
||||
for (NumberInfo sample : samples) {
|
||||
collisionTest.clear();
|
||||
for (Entry<String, PluralRules> entry: keywordToRule.entrySet()) {
|
||||
String keyword = entry.getKey();
|
||||
PluralRules rule = entry.getValue();
|
||||
String foundKeyword = rule.select(sample);
|
||||
if (foundKeyword.equals("other")) {
|
||||
for (ULocale locale : factory.getAvailableULocales()) {
|
||||
PluralRules rules = factory.forLocale(locale);
|
||||
Collection<NumberInfo> samples = rules.getFractionSamples();
|
||||
Map<String,PluralRules> keywordToRule = new HashMap<String,PluralRules>();
|
||||
for (String keyword : rules.getKeywords()) {
|
||||
if (keyword.equals("other")) {
|
||||
continue;
|
||||
}
|
||||
String old = collisionTest.get(sample);
|
||||
if (old != null) {
|
||||
errln(locale + "\tNon-unique rules: " + sample + " => " + old + " & " + foundKeyword);
|
||||
rule.select(sample);
|
||||
} else {
|
||||
collisionTest.put(sample, foundKeyword);
|
||||
String rules2 = keyword + ":" + rules.getRules(keyword);
|
||||
PluralRules singleRule = PluralRules.createRules(rules2);
|
||||
if (singleRule == null) {
|
||||
errln("Can't generate single rule for " + rules2);
|
||||
PluralRules.createRules(rules2); // for debugging
|
||||
continue main;
|
||||
}
|
||||
keywordToRule.put(keyword, singleRule);
|
||||
}
|
||||
Map<NumberInfo, String> collisionTest = new TreeMap();
|
||||
for (NumberInfo sample : samples) {
|
||||
collisionTest.clear();
|
||||
for (Entry<String, PluralRules> entry: keywordToRule.entrySet()) {
|
||||
String keyword = entry.getKey();
|
||||
PluralRules rule = entry.getValue();
|
||||
String foundKeyword = rule.select(sample);
|
||||
if (foundKeyword.equals("other")) {
|
||||
continue;
|
||||
}
|
||||
String old = collisionTest.get(sample);
|
||||
if (old != null) {
|
||||
errln(locale + "\tNon-unique rules: " + sample + " => " + old + " & " + foundKeyword);
|
||||
rule.select(sample);
|
||||
} else {
|
||||
collisionTest.put(sample, foundKeyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCategoriesAndExpected(String title, String categoriesAndExpected, PluralRules rules) {
|
||||
|
@ -224,14 +230,19 @@ public class PluralRulesTest extends TestFmwk {
|
|||
}
|
||||
|
||||
private static String[][] equalityTestData = {
|
||||
{ "a: n is 5",
|
||||
"a: n in 2..6 and n not in 2..4 and n is not 6" },
|
||||
{ "a: n in 2..3",
|
||||
"a: n is 2 or n is 3",
|
||||
"a: n is 3 and n in 2..5 or n is 2" },
|
||||
{ "a: n is 12; b:n mod 10 in 2..3",
|
||||
"b: n mod 10 in 2..3 and n is not 12; a: n in 12..12",
|
||||
"b: n is 13; a: n is 12; b: n mod 10 is 2 or n mod 10 is 3" },
|
||||
// once we add fractions, we had to retract the "test all possibilities" for equality,
|
||||
// so we only have a limited set of equality tests now.
|
||||
{ "a:n in 2;b:n in 5",
|
||||
"b: n in 5;a: n in 2;" },
|
||||
|
||||
// { "a: n is 5",
|
||||
// "a: n in 2..6 and n not in 2..4 and n is not 6" },
|
||||
// { "a: n in 2..3",
|
||||
// "a: n is 2 or n is 3",
|
||||
// "a: n is 3 and n in 2..5 or n is 2" },
|
||||
// { "a: n is 12; b:n mod 10 in 2..3",
|
||||
// "b: n mod 10 in 2..3 and n is not 12; a: n in 12..12",
|
||||
// "b: n is 13; a: n is 12; b: n mod 10 is 2 or n mod 10 is 3" },
|
||||
};
|
||||
|
||||
private static String[][] inequalityTestData = {
|
||||
|
@ -240,7 +251,10 @@ public class PluralRulesTest extends TestFmwk {
|
|||
},
|
||||
{ "a: n mod 3 is 2 and n is not 5",
|
||||
"a: n mod 6 is 2 or n is 8 or n is 11"
|
||||
}
|
||||
},
|
||||
// the following are currently inequal, but we may make them equal in the future.
|
||||
{ "a: n in 2..5",
|
||||
"a: n in 2..4,5" },
|
||||
};
|
||||
|
||||
private void compareEquality(String id, Object[] objects, boolean shouldBeEqual) {
|
||||
|
@ -655,4 +669,37 @@ public class PluralRulesTest extends TestFmwk {
|
|||
"cy; zero: 0, 0.0; one: 1, 1.0; two: 2; few: 3; many: 6; other: 0.1, 2.5, 3.5, 5",
|
||||
};
|
||||
|
||||
}
|
||||
private <T extends Serializable> T serializeAndDeserialize(T original, Output<Integer> size) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream ostream = new ObjectOutputStream(baos);
|
||||
ostream.writeObject(original);
|
||||
ostream.flush();
|
||||
byte bytes[] = baos.toByteArray();
|
||||
size.value = bytes.length;
|
||||
ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
T reconstituted = (T)istream.readObject();
|
||||
return reconstituted;
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestSerialization() {
|
||||
Output<Integer> size = new Output<Integer>();
|
||||
int max = 0;
|
||||
for (ULocale locale : PluralRules.getAvailableULocales()) {
|
||||
PluralRules item = PluralRules.forLocale(locale);
|
||||
PluralRules item2 = serializeAndDeserialize(item, size);
|
||||
logln(locale + "\tsize:\t" + size.value);
|
||||
max = Math.max(max, size.value);
|
||||
if (!assertEquals(locale + "\tPlural rules before and after serialization", item, item2)) {
|
||||
PluralRules item3 = serializeAndDeserialize(item, size);
|
||||
item.equals(item2);
|
||||
}
|
||||
}
|
||||
logln("max \tsize:\t" + max);
|
||||
}
|
||||
}
|
|
@ -6,23 +6,39 @@
|
|||
*/
|
||||
package com.ibm.icu.dev.test.format;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.ibm.icu.dev.test.format.PluralRulesTest.StandardPluralCategories;
|
||||
import com.ibm.icu.dev.util.CollectionUtilities;
|
||||
import com.ibm.icu.dev.util.Relation;
|
||||
import com.ibm.icu.impl.Row;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.text.PluralRules.NumberInfo;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
@ -31,214 +47,53 @@ import com.ibm.icu.util.ULocale;
|
|||
* @author markdavis
|
||||
*/
|
||||
public class WritePluralRulesData {
|
||||
|
||||
// TODO use options
|
||||
public static final String TARGETDIR = "/Users/markdavis/Google Drive/Backup-2012-10-09/Documents/indigo/Generated/icu/plurals/";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
args = new String[] {"rules"};
|
||||
}
|
||||
for (String arg : args) {
|
||||
if (arg.equalsIgnoreCase("samples")) {
|
||||
generateSamples();
|
||||
generateSamples(SampleStyle.modified);
|
||||
} else if (arg.equalsIgnoreCase("original")) {
|
||||
generateSamples(SampleStyle.original);
|
||||
} else if (arg.startsWith("verify")) {
|
||||
generateSamples(SampleStyle.verify);
|
||||
} else if (arg.equalsIgnoreCase("rules")) {
|
||||
showRules();
|
||||
} else if (arg.equalsIgnoreCase("oldSnap")) {
|
||||
generateLOCALE_SNAPSHOT(PluralRulesFactory.NORMAL);
|
||||
} else if (arg.equalsIgnoreCase("newSnap")) {
|
||||
generateLOCALE_SNAPSHOT(PluralRulesFactory.ALTERNATE);
|
||||
} else if (arg.equalsIgnoreCase("fromList")) {
|
||||
getOriginalSamples();
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateLOCALE_SNAPSHOT(PluralRulesFactory pluralRulesFactory) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Map<Set<StandardPluralCategories>, Relation<String, ULocale>> keywordsToData = new TreeMap(StandardPluralCategories.SHORTEST_FIRST);
|
||||
for (ULocale locale : pluralRulesFactory.getAvailableULocales()) {
|
||||
builder.setLength(0);
|
||||
PluralRules rules = pluralRulesFactory.forLocale(locale);
|
||||
boolean firstKeyword = true;
|
||||
EnumSet<StandardPluralCategories> keywords = StandardPluralCategories.getSet(rules.getKeywords());
|
||||
Relation<String, ULocale> samplesToLocales = keywordsToData.get(keywords);
|
||||
if (samplesToLocales == null) {
|
||||
keywordsToData.put(keywords, samplesToLocales = Relation.of(
|
||||
new LinkedHashMap<String,Set<ULocale>>(), LinkedHashSet.class));
|
||||
}
|
||||
//System.out.println(locale);
|
||||
for (StandardPluralCategories keyword : keywords) {
|
||||
if (firstKeyword) {
|
||||
firstKeyword = false;
|
||||
} else {
|
||||
builder.append(";\t");
|
||||
}
|
||||
Collection<NumberInfo> samples = rules.getFractionSamples(keyword.toString());
|
||||
if (samples.size() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
builder.append(keyword).append(": ");
|
||||
boolean first = true;
|
||||
for (NumberInfo n : samples) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(n);
|
||||
// for (double j : samples) {
|
||||
// double sample = i + j/100;
|
||||
// }
|
||||
}
|
||||
}
|
||||
samplesToLocales.put(builder.toString(), locale);
|
||||
}
|
||||
System.out.println(" static final String[] LOCALE_SNAPSHOT = {");
|
||||
for (Entry<Set<StandardPluralCategories>, Relation<String, ULocale>> keywordsAndData : keywordsToData.entrySet()) {
|
||||
System.out.println("\n // " + keywordsAndData.getKey());
|
||||
for (Entry<String, Set<ULocale>> samplesAndLocales : keywordsAndData.getValue().keyValuesSet()) {
|
||||
Set<ULocale> locales = samplesAndLocales.getValue();
|
||||
// check functional equivalence
|
||||
boolean[] isAvailable = new boolean[1];
|
||||
for (ULocale locale : locales) {
|
||||
ULocale base = pluralRulesFactory.getFunctionalEquivalent(locale, isAvailable);
|
||||
if (!locales.contains(base) && base.toString().length() != 0) {
|
||||
System.out.println("**" + locales + " doesn't contain " + base);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(
|
||||
" \"" + CollectionUtilities.join(locales, ",")
|
||||
+ ";\t" + samplesAndLocales.getKey() + "\",");
|
||||
}
|
||||
}
|
||||
System.out.println(" };");
|
||||
}
|
||||
|
||||
private static class OldNewData extends Row.R4<String, String, String, String> {
|
||||
public OldNewData(String oldRules, String oldSamples, String newRules, String newSamples) {
|
||||
super(oldRules, oldSamples, newRules, newSamples);
|
||||
}
|
||||
}
|
||||
|
||||
static final String[] FOCUS_LOCALES = ("af,am,ar,az,bg,bn,ca,cs,cy,da,de,el,en,es,et,eu,fa,fi,fil,fr,gl,gu," +
|
||||
"hi,hr,hu,hy,id,is,it,he,ja,ka,kk,km,kn,ko,ky,lo,lt,lv,mk,ml,mn,mr,ms,my,ne,nl,nb," +
|
||||
"pa,pl,ps,pt,ro,ru,si,sk,sl,sq,sr,sv,sw,ta,te,th,tr,uk,ur,uz,vi,zh,zu").split("\\s*,\\s*");
|
||||
|
||||
public static void showRules() {
|
||||
if (true) {
|
||||
// for debugging
|
||||
PluralRules rules = PluralRulesFactory.ALTERNATE.forLocale(new ULocale("lv"));
|
||||
rules.select(2.0d, 2, 0);
|
||||
}
|
||||
// System.out.println(new TreeSet(Arrays.asList(locales)));
|
||||
Relation<Map<String,OldNewData>, String> rulesToLocale = Relation.of(
|
||||
new TreeMap<Map<String,OldNewData>, Set<String>>(
|
||||
new CollectionUtilities.MapComparator<String,OldNewData>()), TreeSet.class);
|
||||
for (String localeString : FOCUS_LOCALES) {
|
||||
ULocale locale = new ULocale(localeString);
|
||||
PluralRules oldRules = PluralRulesFactory.NORMAL.forLocale(locale);
|
||||
PluralRules newRules = PluralRulesFactory.ALTERNATE.hasOverride(locale) ? PluralRulesFactory.ALTERNATE.forLocale(locale) : null;
|
||||
Set<String> keywords = oldRules.getKeywords();
|
||||
if (newRules != null) {
|
||||
TreeSet<String> temp = new TreeSet<String>(PluralRules.KEYWORD_COMPARATOR);
|
||||
temp.addAll(keywords);
|
||||
temp.addAll(newRules.getKeywords());
|
||||
keywords = temp;
|
||||
}
|
||||
Map<String,OldNewData> temp = new LinkedHashMap();
|
||||
for (String keyword : keywords) {
|
||||
Collection<NumberInfo> oldFractionSamples = oldRules.getFractionSamples(keyword);
|
||||
Collection<NumberInfo> newFractionSamples = newRules == null ? null : newRules.getFractionSamples(keyword);
|
||||
|
||||
// add extra samples if we have some, or if the rules differ
|
||||
|
||||
if (newRules != null) {
|
||||
oldFractionSamples = oldFractionSamples == null ? new TreeSet()
|
||||
: new TreeSet(oldFractionSamples);
|
||||
newFractionSamples = newFractionSamples == null ? new TreeSet()
|
||||
: new TreeSet(newFractionSamples);
|
||||
// if (extraSamples != null) {
|
||||
// for (NumberPlus sample : extraSamples) {
|
||||
// if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
// oldFractionSamples.add(sample);
|
||||
// }
|
||||
// if (newRules != null && newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
// newFractionSamples.add(sample);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if the rules differ, then add samples from each to the other
|
||||
if (newRules != null) {
|
||||
for (NumberInfo sample : oldRules.getFractionSamples()) {
|
||||
if (newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
newFractionSamples.add(sample);
|
||||
}
|
||||
}
|
||||
for (NumberInfo sample : newRules.getFractionSamples()) {
|
||||
if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
oldFractionSamples.add(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String oldRulesString = oldRules.getRules(keyword);
|
||||
if (oldRulesString == null) {
|
||||
oldRulesString = "";
|
||||
}
|
||||
String newRulesString = newRules == null ? "" : newRules.getRules(keyword);
|
||||
if (newRulesString == null) {
|
||||
newRulesString = "";
|
||||
}
|
||||
temp.put(keyword, new OldNewData(
|
||||
oldRulesString,
|
||||
oldFractionSamples == null ? "" : "'" + CollectionUtilities.join(oldFractionSamples, ", "),
|
||||
newRulesString,
|
||||
newFractionSamples == null ? "" : "'" + CollectionUtilities.join(newFractionSamples, ", ")
|
||||
));
|
||||
}
|
||||
rulesToLocale.put(temp, locale.toString());
|
||||
}
|
||||
System.out.println("Locales\tPC\tOld Rules\tOld Samples\tNew Rules\tNew Samples");
|
||||
for (Entry<Map<String, OldNewData>, Set<String>> entry : rulesToLocale.keyValuesSet()) {
|
||||
String localeList = CollectionUtilities.join(entry.getValue(), " ");
|
||||
for (Entry<String, OldNewData> keywordRulesSamples : entry.getKey().entrySet()) {
|
||||
System.out.println(
|
||||
localeList // locale
|
||||
+ "\t" + keywordRulesSamples.getKey() // keyword
|
||||
+ "\t" + keywordRulesSamples.getValue().get0() // rules
|
||||
+ "\t" + keywordRulesSamples.getValue().get1() // samples
|
||||
+ "\t" + keywordRulesSamples.getValue().get2() // rules
|
||||
+ "\t" + keywordRulesSamples.getValue().get3() // samples
|
||||
);
|
||||
localeList = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (false) {
|
||||
System.out.println("\n\nOld Rules for Locales");
|
||||
for (String localeString : FOCUS_LOCALES) {
|
||||
ULocale locale = new ULocale(localeString);
|
||||
PluralRules oldRules = PluralRules.forLocale(locale);
|
||||
System.out.println("{\"" + locale.toString() + "\", \"" + oldRules.toString() + "\"},");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String[][] SAMPLE_PATTERNS = {
|
||||
{"af", "one", "{0} dag"},
|
||||
{"af", "other", "{0} dae"},
|
||||
{"am", "one", "{0} ቀን"},
|
||||
{"am", "other", "{0} ቀናት"}, // fixed to 'other'
|
||||
{"ar", "few", "{0} ساعات"},
|
||||
{"ar", "many", "{0} ساعة"},
|
||||
{"ar", "many", "{0} ساعة"},
|
||||
{"ar", "one", "ساعة"},
|
||||
{"ar", "other", "{0} ساعة"},
|
||||
{"ar", "two", "ساعتان"},
|
||||
{"ar", "zero", "{0} ساعة"},
|
||||
{"bg", "one", "{0} ден"},
|
||||
{"bg", "other", "{0} дена"},
|
||||
{"bn", "one", "{0} টি আপেল"},
|
||||
{"bn", "other", "আমার অনেকগুলি আপেল আছে"},
|
||||
{"bn", "other", "{0} টি আপেল"},
|
||||
//{"bn", "other", "আমার অনেকগুলি আপেল আছে"},
|
||||
{"br", "few", "{0} deiz"},
|
||||
{"br", "many", "{0} a zeizioù"},
|
||||
{"br", "one", "{0} deiz"},
|
||||
|
@ -289,14 +144,10 @@ public class WritePluralRulesData {
|
|||
{"hr", "few", "za {0} mjeseca"},
|
||||
{"hr", "many", "za {0} mjeseci"},
|
||||
{"hr", "one", "za {0} mjesec"},
|
||||
{"hr", "other", "za sljedeći broj mjeseci: {0}"},
|
||||
{"hr", "other", "za {0} mjeseci"},
|
||||
{"hu", "other", "{0} nap"},
|
||||
{"hy", "few", "{0} օր"},
|
||||
{"hy", "many", "{0} օր"},
|
||||
{"hy", "one", "{0} օր"},
|
||||
{"hy", "other", "{0} օր"},
|
||||
{"hy", "two", "{0} օր"},
|
||||
{"hy", "zero", "{0} օր"},
|
||||
{"hy", "one", "այդ {0} ժամը"},
|
||||
{"hy", "other", "այդ {0} ժամերը"},
|
||||
{"id", "other", "{0} hari"},
|
||||
{"is", "one", "{0} dagur"},
|
||||
{"is", "other", "{0} dagar"},
|
||||
|
@ -380,6 +231,333 @@ public class WritePluralRulesData {
|
|||
{"zu", "one", "{0} usuku"}, // added from spreadsheet
|
||||
{"zu", "other", "{0} izinsuku"}, // added from spreadsheet
|
||||
};
|
||||
|
||||
static final Map<ULocale, SamplePatterns> localeToSamplePatterns = new LinkedHashMap();
|
||||
static {
|
||||
for (String[] row : SAMPLE_PATTERNS) {
|
||||
ULocale locale = new ULocale(row[0]);
|
||||
String keyword = row[1];
|
||||
String sample = row[2];
|
||||
SamplePatterns samplePatterns = localeToSamplePatterns.get(locale);
|
||||
if (samplePatterns == null) {
|
||||
localeToSamplePatterns.put(locale, samplePatterns = new SamplePatterns());
|
||||
}
|
||||
samplePatterns.put(keyword, sample);
|
||||
}
|
||||
}
|
||||
|
||||
static final String[][] ORIGINAL_SAMPLES = {
|
||||
{"af", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"am", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ar", "0.0, 0.1, 0.2, 0.4, 1.0, 1.2, 1.4, 2.0, 2.1, 2.4, 4.0, 4.1, 4.2, 12.0, 12.1, 12.2, 12.4, 101.0, 101.1, 101.2, 101.4, 0.00, 0.01, 0.02, 0.04, 0.30, 0.21, 0.22, 0.14, 1.00, 1.02, 1.04, 1.30, 1.21, 1.22, 1.14, 2.00, 2.01, 2.04, 2.30, 2.21, 2.22, 2.14, 4.00, 4.01, 4.02, 4.30, 4.21, 4.22, 4.14, 12.00, 12.01, 12.02, 12.04, 101.00, 101.01, 101.02, 101.04, 101.30, 101.21, 101.22, 101.14, 0.000, 0.001, 0.002, 0.110, 0.004, 0.030, 0.021, 0.022, 0.014, 0.200, 0.201, 0.202, 1.000, 1.002, 1.110, 1.004, 1.030, 1.021, 1.022, 1.014, 1.200, 1.201, 1.202, 2.000, 2.001, 2.110, 2.004, 2.030, 2.021, 2.022, 2.014, 2.200, 2.201, 2.202, 4.000, 4.001, 4.002, 4.030, 4.021, 4.022, 4.014, 4.200, 4.201, 4.202, 12.000, 12.001, 12.002, 12.110, 12.004, 12.200, 12.201, 12.202, 101.000, 101.001, 101.002, 101.110, 101.004, 101.030, 101.021, 101.022, 101.014"},
|
||||
{"bg", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"bn", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"br", "0.0, 0.4, 0.6, 21.0, 21.4, 21.6, 22.0, 22.4, 22.6, 4.0, 4.6, 1000000.0, 1000000.4, 1000000.6, 6.0, 6.4, 0.00, 0.21, 0.22, 0.04, 0.20, 0.71, 0.72, 0.14, 0.06, 21.00, 21.22, 21.04, 21.20, 21.71, 21.72, 21.14, 21.06, 22.00, 22.21, 22.04, 22.20, 22.71, 22.72, 22.14, 22.06, 4.00, 4.21, 4.22, 4.20, 4.71, 4.72, 4.14, 4.06, 1000000.00, 1000000.21, 1000000.22, 1000000.04, 1000000.20, 1000000.71, 1000000.72, 1000000.14, 1000000.06, 6.00, 6.21, 6.22, 6.04, 0.000, 0.021, 0.022, 0.004, 0.020, 0.071, 0.072, 0.014, 0.006, 21.000, 21.022, 21.004, 21.020, 21.071, 21.072, 21.014, 21.006, 22.000, 22.021, 22.004, 22.020, 22.071, 22.072, 22.014, 22.006, 4.000, 4.021, 4.022, 4.020, 4.071, 4.072, 4.014, 4.006, 1000000.000, 1000000.021, 1000000.022, 1000000.004, 1000000.020, 1000000.071, 1000000.072, 1000000.014, 1000000.006, 6.000, 6.021, 6.022, 6.004"},
|
||||
{"ca", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"cs", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"},
|
||||
{"da", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"de", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"dz", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"el", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"es", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"et", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"eu", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"fa", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"fi", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"fil", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"fr", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"gl", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"gu", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"he", "0.0, 0.1, 0.2, 0.4, 1.0, 1.2, 1.4, 2.0, 2.1, 2.4, 20.0, 20.1, 20.2, 20.4, 4.0, 4.1, 4.2, 0.00, 0.01, 0.02, 0.20, 0.21, 0.22, 0.04, 1.00, 1.02, 1.20, 1.21, 1.22, 1.04, 2.00, 2.01, 2.20, 2.21, 2.22, 2.04, 20.00, 20.01, 20.02, 20.21, 20.22, 20.04, 4.00, 4.01, 4.02, 4.20, 0.000, 0.001, 0.002, 0.020, 0.021, 0.022, 0.004, 1.000, 1.002, 1.020, 1.021, 1.022, 1.004, 2.000, 2.001, 2.020, 2.021, 2.022, 2.004, 20.000, 20.001, 20.002, 20.021, 20.022, 20.004, 4.000, 4.001, 4.002, 4.020"},
|
||||
{"hi", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"hr", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"},
|
||||
{"hu", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"id", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"is", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"it", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ja", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"km", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"kn", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"ko", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"lo", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"lt", "0.0, 0.3, 21.0, 21.3, 3.0, 11.0, 11.3, 0.00, 0.21, 0.03, 0.20, 0.13, 21.00, 21.03, 21.20, 21.13, 3.00, 3.21, 3.20, 3.13, 11.00, 11.21, 11.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 21.000, 21.003, 21.020, 21.111, 21.013, 3.000, 3.021, 3.020, 3.111, 3.013, 11.000, 11.021, 11.003"},
|
||||
{"lv", "0.0, 0.3, 21.0, 21.3, 3.0, 0.00, 0.21, 0.20, 0.03, 21.00, 21.20, 21.03, 3.00, 3.21, 0.000, 0.021, 0.020, 0.111, 0.003, 21.000, 21.020, 21.111, 21.003, 3.000, 3.021"},
|
||||
{"ml", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"mr", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ms", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"nb", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ne", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"nl", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"pl", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"},
|
||||
{"pt", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"pt_PT", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ro", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 21.0, 21.1, 21.3, 0.00, 0.01, 0.03, 0.30, 0.31, 0.23, 1.00, 1.03, 1.30, 1.31, 1.23, 3.00, 3.01, 3.30, 3.31, 3.23, 21.00, 21.01, 21.03, 0.000, 0.001, 0.110, 0.101, 0.003, 0.030, 0.031, 0.023, 1.000, 1.110, 1.101, 1.003, 1.030, 1.031, 1.023, 3.000, 3.001, 3.030, 3.031, 3.023, 21.000, 21.001, 21.110, 21.101, 21.003"},
|
||||
{"ru", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"},
|
||||
{"si", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"sk", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"},
|
||||
{"sl", "0.0, 0.4, 0.6, 101.0, 101.4, 101.6, 102.0, 102.4, 102.6, 4.0, 4.6, 6.0, 6.4, 0.00, 0.04, 0.20, 0.21, 0.22, 0.14, 0.06, 101.00, 101.04, 101.20, 101.21, 101.22, 101.14, 101.06, 102.00, 102.04, 102.20, 102.21, 102.22, 102.14, 102.06, 4.00, 4.20, 4.21, 4.22, 4.14, 4.06, 6.00, 6.04, 0.000, 0.101, 0.102, 0.004, 0.020, 0.021, 0.022, 0.014, 0.006, 101.000, 101.102, 101.004, 101.020, 101.021, 101.022, 101.014, 101.006, 102.000, 102.101, 102.004, 102.020, 102.021, 102.022, 102.014, 102.006, 4.000, 4.101, 4.102, 4.020, 4.021, 4.022, 4.014, 4.006, 6.000, 6.101, 6.102, 6.004"},
|
||||
{"sr", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"},
|
||||
{"sv", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"sw", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"ta", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"te", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"th", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"tr", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"uk", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"},
|
||||
{"ur", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"},
|
||||
{"vi", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"zh", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
{"zh_Hant", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"},
|
||||
};
|
||||
static final Map<ULocale,List<NumberInfo>> LOCALE_TO_ORIGINALS = new HashMap();
|
||||
static {
|
||||
for (String[] pair : ORIGINAL_SAMPLES) {
|
||||
ArrayList<NumberInfo> row = new ArrayList();
|
||||
for (String s : pair[1].split("\\s*,\\s*")) {
|
||||
row.add(new NumberInfo(s));
|
||||
}
|
||||
LOCALE_TO_ORIGINALS.put(new ULocale(pair[0]), row);
|
||||
}
|
||||
}
|
||||
|
||||
public static void getOriginalSamples() {
|
||||
try {
|
||||
File file = new File("/Users/markdavis/workspace/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt");
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
|
||||
Map<String,String> localeToSamples = new TreeMap();
|
||||
Matcher m = Pattern.compile("\\d+[.]\\d+").matcher("");
|
||||
while (true) {
|
||||
String line = br.readLine();
|
||||
if (line == null) break;
|
||||
String[] parts = line.split("\t");
|
||||
String locale = parts[0];
|
||||
String pattern = parts[1];
|
||||
boolean found = m.reset(pattern).find();
|
||||
String sample = found
|
||||
? m.group()
|
||||
: "-1";
|
||||
String samples = localeToSamples.get(locale);
|
||||
localeToSamples.put(locale, samples == null ? sample : samples + ", " + sample);
|
||||
}
|
||||
br.close();
|
||||
for (Entry<String, String> entry : localeToSamples.entrySet()) {
|
||||
System.out.println("{\"" + entry.getKey() + "\", \"" + entry.getValue() + "\"},");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateLOCALE_SNAPSHOT(PluralRulesFactory pluralRulesFactory) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Map<Set<StandardPluralCategories>, Relation<String, ULocale>> keywordsToData = new TreeMap(StandardPluralCategories.SHORTEST_FIRST);
|
||||
for (ULocale locale : pluralRulesFactory.getAvailableULocales()) {
|
||||
builder.setLength(0);
|
||||
PluralRules rules = pluralRulesFactory.forLocale(locale);
|
||||
boolean firstKeyword = true;
|
||||
EnumSet<StandardPluralCategories> keywords = StandardPluralCategories.getSet(rules.getKeywords());
|
||||
Relation<String, ULocale> samplesToLocales = keywordsToData.get(keywords);
|
||||
if (samplesToLocales == null) {
|
||||
keywordsToData.put(keywords, samplesToLocales = Relation.of(
|
||||
new LinkedHashMap<String,Set<ULocale>>(), LinkedHashSet.class));
|
||||
}
|
||||
//System.out.println(locale);
|
||||
for (StandardPluralCategories keyword : keywords) {
|
||||
if (firstKeyword) {
|
||||
firstKeyword = false;
|
||||
} else {
|
||||
builder.append(";\t");
|
||||
}
|
||||
Collection<NumberInfo> samples = rules.getFractionSamples(keyword.toString());
|
||||
if (samples.size() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
builder.append(keyword).append(": ");
|
||||
boolean first = true;
|
||||
for (NumberInfo n : samples) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(n);
|
||||
// for (double j : samples) {
|
||||
// double sample = i + j/100;
|
||||
// }
|
||||
}
|
||||
}
|
||||
samplesToLocales.put(builder.toString(), locale);
|
||||
}
|
||||
System.out.println(" static final String[] LOCALE_SNAPSHOT = {");
|
||||
for (Entry<Set<StandardPluralCategories>, Relation<String, ULocale>> keywordsAndData : keywordsToData.entrySet()) {
|
||||
System.out.println("\n // " + keywordsAndData.getKey());
|
||||
for (Entry<String, Set<ULocale>> samplesAndLocales : keywordsAndData.getValue().keyValuesSet()) {
|
||||
Set<ULocale> locales = samplesAndLocales.getValue();
|
||||
// check functional equivalence
|
||||
boolean[] isAvailable = new boolean[1];
|
||||
for (ULocale locale : locales) {
|
||||
ULocale base = pluralRulesFactory.getFunctionalEquivalent(locale, isAvailable);
|
||||
if (!locales.contains(base) && base.toString().length() != 0) {
|
||||
System.out.println("**" + locales + " doesn't contain " + base);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(
|
||||
" \"" + CollectionUtilities.join(locales, ",")
|
||||
+ ";\t" + samplesAndLocales.getKey() + "\",");
|
||||
}
|
||||
}
|
||||
System.out.println(" };");
|
||||
}
|
||||
|
||||
private static class OldNewData extends Row.R5<String, String, String, String, String> {
|
||||
public OldNewData(String oldRules, String oldSamples, String newRules, String newSamples, String intDiff) {
|
||||
super(oldRules, oldSamples, newRules, newSamples, intDiff);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showRules() {
|
||||
if (true) {
|
||||
// for debugging
|
||||
PluralRules rules = PluralRulesFactory.ALTERNATE.forLocale(new ULocale("lv"));
|
||||
rules.select(2.0d, 2, 0);
|
||||
}
|
||||
// System.out.println(new TreeSet(Arrays.asList(locales)));
|
||||
Relation<Map<String,OldNewData>, String> rulesToLocale = Relation.of(
|
||||
new TreeMap<Map<String,OldNewData>, Set<String>>(
|
||||
new CollectionUtilities.MapComparator<String,OldNewData>()), TreeSet.class);
|
||||
for (String localeString : FOCUS_LOCALES) {
|
||||
ULocale locale = new ULocale(localeString);
|
||||
PluralRules oldRules = PluralRulesFactory.NORMAL.forLocale(locale);
|
||||
PluralRules newRules = PluralRulesFactory.ALTERNATE.hasOverride(locale) ? PluralRulesFactory.ALTERNATE.forLocale(locale) : null;
|
||||
Set<String> keywords = oldRules.getKeywords();
|
||||
if (newRules != null) {
|
||||
TreeSet<String> temp = new TreeSet<String>(PluralRules.KEYWORD_COMPARATOR);
|
||||
temp.addAll(keywords);
|
||||
temp.addAll(newRules.getKeywords());
|
||||
keywords = temp;
|
||||
}
|
||||
Map<String,OldNewData> temp = new LinkedHashMap();
|
||||
for (String keyword : keywords) {
|
||||
Collection<NumberInfo> oldFractionSamples = oldRules.getFractionSamples(keyword);
|
||||
Collection<NumberInfo> newFractionSamples = newRules == null ? null : newRules.getFractionSamples(keyword);
|
||||
|
||||
// add extra samples if we have some, or if the rules differ
|
||||
|
||||
if (newRules != null) {
|
||||
oldFractionSamples = oldFractionSamples == null ? new TreeSet()
|
||||
: new TreeSet(oldFractionSamples);
|
||||
newFractionSamples = newFractionSamples == null ? new TreeSet()
|
||||
: new TreeSet(newFractionSamples);
|
||||
// if (extraSamples != null) {
|
||||
// for (NumberPlus sample : extraSamples) {
|
||||
// if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
// oldFractionSamples.add(sample);
|
||||
// }
|
||||
// if (newRules != null && newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) {
|
||||
// newFractionSamples.add(sample);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if the rules differ, then add samples from each to the other
|
||||
if (newRules != null) {
|
||||
for (NumberInfo sample : oldRules.getFractionSamples()) {
|
||||
if (newRules.select(sample).equals(keyword)) {
|
||||
newFractionSamples.add(sample);
|
||||
}
|
||||
}
|
||||
for (NumberInfo sample : newRules.getFractionSamples()) {
|
||||
if (oldRules.select(sample).equals(keyword)) {
|
||||
oldFractionSamples.add(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String intDiff = newRules == null ? "" : getDiffs(oldFractionSamples, newFractionSamples);
|
||||
|
||||
String oldRulesString = rulesForDisplay(oldRules, keyword);
|
||||
if (oldRulesString == null) {
|
||||
oldRulesString = "";
|
||||
}
|
||||
String newRulesString = newRules == null ? "" : rulesForDisplay(newRules, keyword);
|
||||
if (newRulesString == null) {
|
||||
newRulesString = "";
|
||||
}
|
||||
if (oldRulesString.length() == 0 && newRulesString.length() != 0) {
|
||||
oldRulesString = "<NEW SPLITS>";
|
||||
} else if (oldRulesString.length() != 0 && newRulesString.length() == 0 && newRules != null) {
|
||||
newRulesString = "<NEW MERGES>";
|
||||
}
|
||||
temp.put(keyword, new OldNewData(
|
||||
oldRulesString,
|
||||
oldFractionSamples == null ? "" : "'" + CollectionUtilities.join(oldFractionSamples, ", "),
|
||||
newRulesString,
|
||||
newFractionSamples == null ? "" : "'" + CollectionUtilities.join(newFractionSamples, ", "),
|
||||
intDiff.length() == 0 ? "" : "'" + intDiff
|
||||
));
|
||||
}
|
||||
rulesToLocale.put(temp, locale.toString());
|
||||
}
|
||||
System.out.println("Locales\tPC\tOld Rules\tOld Sample Numbers\tNew Rules\tNew Sample Numbers\tInt-Diff");
|
||||
for (Entry<Map<String, OldNewData>, Set<String>> entry : rulesToLocale.keyValuesSet()) {
|
||||
String localeList = CollectionUtilities.join(entry.getValue(), " ");
|
||||
for (Entry<String, OldNewData> keywordRulesSamples : entry.getKey().entrySet()) {
|
||||
System.out.println(
|
||||
localeList // locale
|
||||
+ "\t" + keywordRulesSamples.getKey() // keyword
|
||||
+ "\t" + keywordRulesSamples.getValue().get0() // rules
|
||||
+ "\t" + keywordRulesSamples.getValue().get1() // samples
|
||||
+ "\t" + keywordRulesSamples.getValue().get2() // rules
|
||||
+ "\t" + keywordRulesSamples.getValue().get3() // samples
|
||||
+ "\t" + keywordRulesSamples.getValue().get4() // int diff
|
||||
);
|
||||
localeList = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (false) {
|
||||
System.out.println("\n\nOld Rules for Locales");
|
||||
for (String localeString : FOCUS_LOCALES) {
|
||||
ULocale locale = new ULocale(localeString);
|
||||
PluralRules oldRules = PluralRules.forLocale(locale);
|
||||
System.out.println("{\"" + locale.toString() + "\", \"" + oldRules.toString() + "\"},");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param oldFractionSamples
|
||||
* @param newFractionSamples
|
||||
* @return
|
||||
*/
|
||||
private static String getDiffs(Collection<NumberInfo> oldFractionSamples,
|
||||
Collection<NumberInfo> newFractionSamples) {
|
||||
oldFractionSamples = oldFractionSamples == null ? Collections.EMPTY_SET : oldFractionSamples;
|
||||
newFractionSamples = newFractionSamples == null ? Collections.EMPTY_SET : newFractionSamples;
|
||||
|
||||
TreeSet<NumberInfo> additions = new TreeSet(newFractionSamples);
|
||||
additions.removeAll(oldFractionSamples);
|
||||
TreeSet<NumberInfo> removals = new TreeSet(oldFractionSamples);
|
||||
removals.removeAll(newFractionSamples);
|
||||
StringBuffer result = new StringBuffer();
|
||||
addInts(additions, "+", result);
|
||||
addInts(removals, "-", result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static void addInts(TreeSet<NumberInfo> additions, String title, StringBuffer result) {
|
||||
for (NumberInfo n : additions) {
|
||||
if (n.visibleFractionDigitCount == 0) {
|
||||
if (result.length() != 0) {
|
||||
result.append("; ");
|
||||
}
|
||||
result.append(title).append(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final Set<String> NEW_LOCALES = new HashSet(Arrays.asList("az,ka,kk,ky,mk,mn,my,pa,ps,sq,uz".split("\\s*,\\s*")));
|
||||
|
||||
static class SamplePatterns {
|
||||
|
@ -389,7 +567,7 @@ public class WritePluralRulesData {
|
|||
if (keywordToPattern.containsKey(keyword)) {
|
||||
throw new IllegalArgumentException("Duplicate keyword <" + keyword + ">");
|
||||
} else {
|
||||
keywordToPattern.put(keyword, sample);
|
||||
keywordToPattern.put(keyword, sample.replace(" ", "\u00A0"));
|
||||
}
|
||||
}
|
||||
public void checkErrors(Set<String> set) {
|
||||
|
@ -397,7 +575,7 @@ public class WritePluralRulesData {
|
|||
for (String keyword : set) {
|
||||
String error = "";
|
||||
String sample = keywordToPattern.get(keyword);
|
||||
String skeleton = sample.replace(" ", "").replace("{0}", "");
|
||||
String skeleton = sample.replace(" ", "").replaceAll("\\s*\\{0\\}\\s*", "");
|
||||
String oldSkeletonKeyword = skeletonToKeyword.get(skeleton);
|
||||
if (oldSkeletonKeyword != null) {
|
||||
if (error.length() != 0) {
|
||||
|
@ -416,22 +594,22 @@ public class WritePluralRulesData {
|
|||
}
|
||||
}
|
||||
|
||||
static void generateSamples() {
|
||||
Map<ULocale, SamplePatterns> localeToSamplePatterns = new LinkedHashMap();
|
||||
for (String[] row : SAMPLE_PATTERNS) {
|
||||
ULocale locale = new ULocale(row[0]);
|
||||
String keyword = row[1];
|
||||
String sample = row[2];
|
||||
SamplePatterns samplePatterns = localeToSamplePatterns.get(locale);
|
||||
if (samplePatterns == null) {
|
||||
localeToSamplePatterns.put(locale, samplePatterns = new SamplePatterns());
|
||||
}
|
||||
samplePatterns.put(keyword, sample);
|
||||
}
|
||||
enum SampleStyle {original, modified, verify}
|
||||
|
||||
static void generateSamples(SampleStyle sampleStyle) throws IOException {
|
||||
LinkedHashSet<ULocale> skippedLocales = new LinkedHashSet<ULocale>();
|
||||
System.out.println("Locale\tPC\tPattern\tSample\tErrors");
|
||||
System.out.println("Locale\tPC\tPattern\tSamples\tRules\tErrors (" + sampleStyle + ")");
|
||||
BufferedWriter writer = null;
|
||||
for (String localeString : FOCUS_LOCALES) {
|
||||
ULocale locale = new ULocale(localeString);
|
||||
if (sampleStyle == SampleStyle.verify) {
|
||||
writer = new BufferedWriter(
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream(TARGETDIR + "fraction-" + locale + ".tsv"), Charset.forName("UTF-8")));
|
||||
writer.write("Plural Category\tEnglish Number\tFormatted Sample\tAcceptable?\tReplacement\n");
|
||||
}
|
||||
|
||||
NumberFormat nf = NumberFormat.getInstance(new ULocale(locale.toString()+"@numbers=latn"));
|
||||
PluralRules newRules = PluralRulesFactory.ALTERNATE.forLocale(locale);
|
||||
SamplePatterns samplePatterns = localeToSamplePatterns.get(locale);
|
||||
if (samplePatterns == null && NEW_LOCALES.contains(localeString)) {
|
||||
|
@ -442,108 +620,105 @@ public class WritePluralRulesData {
|
|||
samplePatterns.checkErrors(newRules.getKeywords());
|
||||
// now print.
|
||||
for (String keyword : newRules.getKeywords()) {
|
||||
if (sampleStyle != SampleStyle.modified) {
|
||||
Collection<NumberInfo> samples = getSamples(newRules, keyword,
|
||||
sampleStyle == SampleStyle.verify ? null : locale);
|
||||
for (NumberInfo sample : samples) {
|
||||
String pattern = samplePatterns.keywordToPattern.get(keyword);
|
||||
String str = format(pattern, nf, sample);
|
||||
if (sampleStyle == SampleStyle.verify) {
|
||||
writer.write(keyword + "\t'" + sample + "\t" + str + "\n");
|
||||
} else {
|
||||
System.out.println(locale + "\t" + keyword + "\t" + sample + "\t" + str);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String pattern = null;
|
||||
String error = null;
|
||||
Collection<NumberInfo> samples = newRules.getFractionSamples(keyword);
|
||||
Collection<NumberInfo> samples = getSamples(newRules, keyword, null);
|
||||
NumberInfo first = samples.iterator().next();
|
||||
String sample = "??? " + first.toString();
|
||||
String rule = "";
|
||||
if (samplePatterns == null) {
|
||||
pattern = "???";
|
||||
error = "\tERROR: Locale data missing";
|
||||
} else {
|
||||
pattern = samplePatterns.keywordToPattern.get(keyword);
|
||||
rule = rulesForDisplay(newRules, keyword);
|
||||
error = samplePatterns.keywordToErrors.get(keyword);
|
||||
if (pattern == null) {
|
||||
pattern = "???";
|
||||
error = "\tERROR: Needed for new rules";
|
||||
} else {
|
||||
sample = pattern.replace("{0}", first.toString());
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (NumberInfo x : samples) {
|
||||
if (buffer.length() != 0) {
|
||||
buffer.append("; ");
|
||||
}
|
||||
String str = format(pattern, nf, x);
|
||||
buffer.append(str);
|
||||
}
|
||||
sample = buffer.toString();
|
||||
}
|
||||
}
|
||||
System.out.println(locale + "\t" + keyword
|
||||
+ "\t" + pattern
|
||||
+ "\t" + sample
|
||||
+ "\t" + rule
|
||||
+ error
|
||||
);
|
||||
}
|
||||
if (sampleStyle == SampleStyle.verify) {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
System.out.println("SKIP:\t\t\t" + skippedLocales);
|
||||
}
|
||||
|
||||
private static Collection<NumberInfo> getSamples(PluralRules newRules, String keyword, ULocale locale) {
|
||||
if (locale == null) {
|
||||
return newRules.getFractionSamples(keyword);
|
||||
}
|
||||
Collection<NumberInfo> result = new ArrayList();
|
||||
List<NumberInfo> originals = LOCALE_TO_ORIGINALS.get(locale);
|
||||
if (originals == null) {
|
||||
return newRules.getFractionSamples(keyword);
|
||||
}
|
||||
for (NumberInfo s : originals) {
|
||||
if (keyword.equals(newRules.select(s))) {
|
||||
result.add(s);
|
||||
}
|
||||
}
|
||||
if (result.size() == 0) {
|
||||
return newRules.getFractionSamples(keyword);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String rulesForDisplay(PluralRules newRules, String keyword) {
|
||||
String rule;
|
||||
rule = newRules.getRules(keyword);
|
||||
rule = rule != null ? rule.replace(" ", "\u00A0").replace("\u00A0or", " or")
|
||||
: keyword.equals("other") ? "<all else>"
|
||||
: "";
|
||||
return rule;
|
||||
}
|
||||
|
||||
private static String format(String pattern, NumberFormat nf, NumberInfo x) {
|
||||
nf.setMaximumFractionDigits(x.visibleFractionDigitCount);
|
||||
nf.setMinimumFractionDigits(x.visibleFractionDigitCount);
|
||||
String str = nf.format(x.source);
|
||||
return pattern.replace("{0}", str);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static void generateVerificationSamples() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
static String[][] OLDRULES = {
|
||||
{"af", "one: n is 1"},
|
||||
{"am", "one: n in 0..1"},
|
||||
{"ar", "zero: n is 0; one: n is 1; two: n is 2; few: n mod 100 in 3..10; many: n mod 100 in 11..99"},
|
||||
{"az", "other: null"},
|
||||
{"bg", "one: n is 1"},
|
||||
{"bn", "one: n is 1"},
|
||||
{"ca", "one: n is 1"},
|
||||
{"cs", "one: n is 1; few: n in 2..4"},
|
||||
{"cy", "zero: n is 0; one: n is 1; two: n is 2; few: n is 3; many: n is 6"},
|
||||
{"da", "one: n is 1"},
|
||||
{"de", "one: n is 1"},
|
||||
{"el", "one: n is 1"},
|
||||
{"en", "one: n is 1"},
|
||||
{"es", "one: n is 1"},
|
||||
{"et", "one: n is 1"},
|
||||
{"eu", "one: n is 1"},
|
||||
{"fa", "other: null"},
|
||||
{"fi", "one: n is 1"},
|
||||
{"fil", "one: n in 0..1"},
|
||||
{"fr", "one: n within 0..2 and n is not 2"},
|
||||
{"gl", "one: n is 1"},
|
||||
{"gu", "one: n is 1"},
|
||||
{"hi", "one: n in 0..1"},
|
||||
{"hr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"hu", "other: null"},
|
||||
{"hy", "one: n is 1"},
|
||||
{"id", "other: null"},
|
||||
{"is", "one: n is 1"},
|
||||
{"it", "one: n is 1"},
|
||||
{"he", "one: n is 1; two: n is 2; many: n is not 0 and n mod 10 is 0"},
|
||||
{"ja", "other: null"},
|
||||
{"ka", "other: null"},
|
||||
{"kk", "one: n is 1"},
|
||||
{"km", "other: null"},
|
||||
{"kn", "other: null"},
|
||||
{"ko", "other: null"},
|
||||
{"ky", "one: n is 1"},
|
||||
{"lo", "other: null"},
|
||||
{"lt", "one: n mod 10 is 1 and n mod 100 not in 11..19; few: n mod 10 in 2..9 and n mod 100 not in 11..19"},
|
||||
{"lv", "zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11"},
|
||||
{"mk", "one: n mod 10 is 1 and n is not 11"},
|
||||
{"ml", "one: n is 1"},
|
||||
{"mn", "one: n is 1"},
|
||||
{"mr", "one: n is 1"},
|
||||
{"ms", "other: null"},
|
||||
{"my", "other: null"},
|
||||
{"ne", "one: n is 1"},
|
||||
{"nl", "one: n is 1"},
|
||||
{"nb", "one: n is 1"},
|
||||
{"pa", "one: n is 1"},
|
||||
{"pl", "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14"},
|
||||
{"ps", "one: n is 1"},
|
||||
{"pt", "one: n is 1"},
|
||||
{"ro", "one: n is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"},
|
||||
{"ru", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"si", "other: null"},
|
||||
{"sk", "one: n is 1; few: n in 2..4"},
|
||||
{"sl", "one: n mod 100 is 1; two: n mod 100 is 2; few: n mod 100 in 3..4"},
|
||||
{"sq", "one: n is 1"},
|
||||
{"sr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"sv", "one: n is 1"},
|
||||
{"sw", "one: n is 1"},
|
||||
{"ta", "one: n is 1"},
|
||||
{"te", "one: n is 1"},
|
||||
{"th", "other: null"},
|
||||
{"tr", "other: null"},
|
||||
{"uk", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"},
|
||||
{"ur", "one: n is 1"},
|
||||
{"uz", "other: null"},
|
||||
{"vi", "other: null"},
|
||||
{"zh", "other: null"},
|
||||
{"zu", "one: n is 1"},
|
||||
};
|
||||
|
||||
}
|
||||
|
|
1957
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt
Normal file
1957
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1996-2012, International Business Machines Corporation and *
|
||||
* Copyright (C) 1996-2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -125,6 +125,32 @@ public class CompatibilityTest extends TestFmwk
|
|||
private static final String[][] SKIP_CASES = {
|
||||
{"ICU_3.8.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_3.8.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
// ICU 52 is not serialization-compatible with previous versions.
|
||||
{"ICU_3.8.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_3.8.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.0", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_4.0", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.2.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_4.2.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.4", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_4.4", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.4", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_4.6", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_4.6", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.6", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_4.8", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_4.8", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_4.8", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_49.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_49.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_49.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_50.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_50.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_50.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
{"ICU_51.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"},
|
||||
{"ICU_51.1", "com.ibm.icu.text.PluralFormat.dat"},
|
||||
{"ICU_51.1", "com.ibm.icu.text.PluralRules.dat"},
|
||||
|
||||
{"ICU_3.6", "com.ibm.icu.text.RuleBasedNumberFormat.dat"},
|
||||
{"ICU_3.8.1", "com.ibm.icu.text.RuleBasedNumberFormat.dat"},
|
||||
{"ICU_4.0", "com.ibm.icu.text.RuleBasedNumberFormat.dat"},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (c) 2004-2012, International Business Machines
|
||||
* Copyright (c) 2004-2013, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -2192,6 +2192,19 @@ public class FormatTests
|
|||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PluralRulesSerialProxyHandler implements SerializableTest.Handler {
|
||||
// Tested through PluralRules, so just a stub here to keep CoverageTest happy
|
||||
final String[] cannedRules = {};
|
||||
|
||||
public Object[] getTestObjects() {
|
||||
return new PluralRules[cannedRules.length];
|
||||
}
|
||||
public boolean hasSameBehavior(Object a, Object b) {
|
||||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class TimeUnitFormatHandler implements SerializableTest.Handler {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1996-2012, International Business Machines Corporation and *
|
||||
* Copyright (C) 1996-2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -672,6 +672,7 @@ public class SerializableTest extends TestFmwk.TestGroup
|
|||
map.put("com.ibm.icu.impl.DateNumberFormat", new FormatTests.DateNumberFormatHandler());
|
||||
map.put("com.ibm.icu.text.PluralFormat", new FormatTests.PluralFormatHandler());
|
||||
map.put("com.ibm.icu.text.PluralRules", new FormatTests.PluralRulesHandler());
|
||||
map.put("com.ibm.icu.text.PluralRulesSerialProxy", new FormatTests.PluralRulesSerialProxyHandler());
|
||||
map.put("com.ibm.icu.text.TimeUnitFormat", new FormatTests.TimeUnitFormatHandler());
|
||||
map.put("com.ibm.icu.text.SelectFormat", new FormatTests.SelectFormatHandler());
|
||||
map.put("com.ibm.icu.impl.TimeZoneNamesImpl", new FormatTests.TimeZoneNamesHandler());
|
||||
|
|
Loading…
Add table
Reference in a new issue