001: package net.sf.saxon.number;
002:
003: import net.sf.saxon.om.FastStringBuffer;
004:
005: import java.io.Serializable;
006: import java.util.ArrayList;
007: import java.util.List;
008:
009: /**
010: * Class NumberFormatter defines a method to format a ArrayList of integers as a character
011: * string according to a supplied format specification.
012: * @author Michael H. Kay
013: */
014:
015: public class NumberFormatter implements Serializable {
016:
017: private ArrayList formatTokens;
018: private ArrayList punctuationTokens;
019: private boolean startsWithPunctuation;
020:
021: /**
022: * Tokenize the format pattern.
023: * @param format the format specification. Contains one of the following values:<ul>
024: * <li>"1": conventional decimal numbering</li>
025: * <li>"a": sequence a, b, c, ... aa, ab, ac, ...</li>
026: * <li>"A": sequence A, B, C, ... AA, AB, AC, ...</li>
027: * <li>"i": sequence i, ii, iii, iv, v ...</li>
028: * <li>"I": sequence I, II, III, IV, V, ...</li>
029: * </ul>
030: * This symbol may be preceded and followed by punctuation (any other characters) which is
031: * copied to the output string.
032: */
033:
034: public void prepare(String format) {
035:
036: // Tokenize the format string into alternating alphanumeric and non-alphanumeric tokens
037:
038: if (format.length() == 0)
039: format = "1";
040:
041: formatTokens = new ArrayList(10);
042: punctuationTokens = new ArrayList(10);
043:
044: int len = format.length();
045: int i = 0;
046: int t;
047: boolean first = true;
048: startsWithPunctuation = true;
049:
050: while (i < len) {
051: char c = format.charAt(i);
052: t = i;
053: while (Character.isLetterOrDigit(c)) {
054: i++;
055: if (i == len)
056: break;
057: c = format.charAt(i);
058: }
059: if (i > t) {
060: String tok = format.substring(t, i);
061: formatTokens.add(tok);
062: if (first) {
063: punctuationTokens.add(".");
064: startsWithPunctuation = false;
065: first = false;
066: }
067: }
068: if (i == len)
069: break;
070: t = i;
071: c = format.charAt(i);
072: while (!Character.isLetterOrDigit(c)) {
073: first = false;
074: i++;
075: if (i == len)
076: break;
077: c = format.charAt(i);
078: }
079: if (i > t) {
080: String sep = format.substring(t, i);
081: punctuationTokens.add(sep);
082: }
083: }
084:
085: if (formatTokens.size() == 0) {
086: formatTokens.add("1");
087: if (punctuationTokens.size() == 1) {
088: punctuationTokens.add(punctuationTokens.get(0));
089: }
090: }
091:
092: }
093:
094: /**
095: * Format a list of numbers.
096: * @param numbers the numbers to be formatted (a sequence of integer values; it may also contain
097: * preformatted strings as part of the error recovery fallback)
098: * @return the formatted output string.
099: */
100:
101: public CharSequence format(List numbers, int groupSize,
102: String groupSeparator, String letterValue, String ordinal,
103: Numberer numberer) {
104:
105: FastStringBuffer sb = new FastStringBuffer(20);
106: int num = 0;
107: int tok = 0;
108: // output first punctuation token
109: if (startsWithPunctuation) {
110: sb.append((String) punctuationTokens.get(tok));
111: }
112: // output the list of numbers
113: while (num < numbers.size()) {
114: if (num > 0) {
115: if (tok == 0 && startsWithPunctuation) {
116: // The first punctuation token isn't a separator if it appears before the first
117: // formatting token. Such a punctuation token is used only once, at the start.
118: sb.append(".");
119: } else {
120: sb.append((String) punctuationTokens.get(tok));
121: }
122: }
123: Object o = numbers.get(num++);
124: String s;
125: if (o instanceof Long) {
126: long nr = ((Long) o).longValue();
127:
128: s = numberer
129: .format(nr, (String) formatTokens.get(tok),
130: groupSize, groupSeparator, letterValue,
131: ordinal);
132: } else {
133: s = o.toString();
134: }
135: sb.append(s);
136: tok++;
137: if (tok == formatTokens.size())
138: tok--;
139: }
140: // output the final punctuation token
141: if (punctuationTokens.size() > formatTokens.size()) {
142: sb.append((String) punctuationTokens.get(punctuationTokens
143: .size() - 1));
144: }
145: return sb.condense();
146: }
147:
148: }
149:
150: //
151: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
152: // you may not use this file except in compliance with the License. You may obtain a copy of the
153: // License at http://www.mozilla.org/MPL/
154: //
155: // Software distributed under the License is distributed on an "AS IS" basis,
156: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
157: // See the License for the specific language governing rights and limitations under the License.
158: //
159: // The Original Code is: all this file.
160: //
161: // The Initial Developer of the Original Code is Michael H. Kay.
162: //
163: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
164: //
165: // Contributor(s): none.
166: //
|