001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util.transformers;
011:
012: import java.util.regex.*;
013:
014: /**
015: * Static utilities to deal with roman numbers, and non static functions to transform strings
016: * representing decimal numbers to roman numbers and back.
017: *
018: * @author Michiel Meeuwissen
019: * @since MMBase-1.8
020: * @version $Id: RomanTransformer.java,v 1.6 2007/08/04 08:09:14 michiel Exp $
021: */
022:
023: public class RomanTransformer extends StringTransformer {
024:
025: public static final Pattern NUMERIC = Pattern.compile("\\d+");
026: public static final Pattern ROMAN = Pattern
027: .compile("(?i)[ivxlcdm]+");
028:
029: /**
030: * Constants for roman numbers
031: */
032: public static final int I = 1, V = 5, X = 10, L = 50, C = 100,
033: D = 500, M = 1000;
034:
035: /**
036: * Converts one of the letters from the roman number system to an int.
037: * @return <code>0</code> if could not be converted
038: */
039: public static int romanToDecimal(char r) {
040: if (r == 'i')
041: return I;
042: if (r == 'v')
043: return V;
044: if (r == 'x')
045: return X;
046: if (r == 'l')
047: return L;
048: if (r == 'c')
049: return C;
050: if (r == 'd')
051: return D;
052: if (r == 'm')
053: return M;
054: return 0;
055: }
056:
057: /**
058: * Converts an integer to one the letters of the roman number system, or ' ' if no such number.
059: * @see #decimalToRoman(int)
060: */
061:
062: public static char decimalToRomanDigit(int i) {
063: switch (i) {
064: case M:
065: return 'm';
066: case D:
067: return 'd';
068: case C:
069: return 'c';
070: case L:
071: return 'l';
072: case X:
073: return 'x';
074: case V:
075: return 'v';
076: case I:
077: return 'i';
078: default:
079: return ' ';
080: }
081: }
082:
083: /**
084: * Converts roman number to int.
085: */
086: public static int romanToDecimal(String roman) {
087: roman = roman.toLowerCase();
088: int tot = 0;
089: int mode = I;
090: for (int i = roman.length() - 1; i >= 0; i--) {
091: int value = romanToDecimal(roman.charAt(i));
092:
093: if (value > mode)
094: mode = value;
095: if (value < mode) {
096: tot -= value;
097: } else {
098: tot += value;
099: }
100: }
101:
102: return tot;
103: }
104:
105: /**
106: * Converts int to roman number (if bigger than 0, smaller then 4000), other wise return the
107: * integer as a string.
108: */
109: public static String decimalToRoman(int value) {
110: if (value < 1 || value > 3999) {
111: // throw new IllegalArgumentException("Only natural numbers smaller than 4000 can be
112: // presented as a roman number");
113: return "" + value;
114: }
115: final StringBuilder buf = new StringBuilder();
116: int mode = M;
117: while (value > 0) {
118: while (value < mode)
119: mode /= 10;
120: if (value >= 9 * mode && mode < M) {
121: buf.append(decimalToRomanDigit(mode));
122: buf.append(decimalToRomanDigit(mode * 10));
123: value -= 9 * mode;
124: continue;
125: }
126: if (value >= 4 * mode && mode < M) {
127: if (value < 5 * mode) {
128: buf.append(decimalToRomanDigit(mode));
129: value += mode;
130: }
131: buf.append(decimalToRomanDigit(5 * mode));
132: value -= 5 * mode;
133: }
134: while (value >= mode) {
135: buf.append(decimalToRomanDigit(mode));
136: value -= mode;
137: }
138: }
139: return buf.toString();
140: }
141:
142: // javadoc inherited
143: public String transform(String r) {
144: try {
145: int i = Integer.parseInt(r);
146: return decimalToRoman(i);
147: } catch (Exception e) {
148: return r;
149: }
150: }
151:
152: // javadoc inherited
153: public String transformBack(String r) {
154: return "" + romanToDecimal(r);
155: }
156:
157: public String toString() {
158: return "ROMAN";
159: }
160:
161: /**
162: * Just to test
163: */
164: public static void main(String argv[]) {
165: if (argv.length == 0) {
166: System.out.println("Use roman or decimal argument");
167: return;
168: }
169: if (argv.length == 1) {
170: if (NUMERIC.matcher(argv[0]).matches()) {
171: System.out.println(decimalToRoman(Integer
172: .parseInt(argv[0])));
173: } else {
174: System.out.println(romanToDecimal(argv[0]));
175: }
176: }
177: if (argv.length == 2) {
178: int start = NUMERIC.matcher(argv[0]).matches() ? Integer
179: .parseInt(argv[0]) : romanToDecimal(argv[0]);
180: int end = NUMERIC.matcher(argv[1]).matches() ? Integer
181: .parseInt(argv[1]) : romanToDecimal(argv[1]);
182: for (int i = start; i <= end; i++) {
183: System.out.println(decimalToRoman(i));
184: }
185: }
186: }
187:
188: }
|