DeduceFormat.java
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.timingdiagram;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
final class DeduceFormat {
private final boolean forceSign;
private final char groupingSep;
private final char decimalSep;
private final int minFractionDigits;
private final int maxFractionDigits;
private DeduceFormat(boolean forceSign, char groupingSep, char decimalSep, int minFractionDigits,
int maxFractionDigits) {
this.forceSign = forceSign;
this.groupingSep = groupingSep;
this.decimalSep = decimalSep;
this.minFractionDigits = minFractionDigits;
this.maxFractionDigits = maxFractionDigits;
}
public DeduceFormat mergeWith(DeduceFormat other) {
if (other == null)
return this;
final boolean mergedForceSign = this.forceSign || other.forceSign;
final char mergedDecimal = this.decimalSep != '\0' ? this.decimalSep : other.decimalSep;
char mergedGrouping;
if (this.groupingSep == '\0')
mergedGrouping = other.groupingSep;
else if (other.groupingSep == '\0')
mergedGrouping = this.groupingSep;
else if (this.groupingSep == other.groupingSep)
mergedGrouping = this.groupingSep;
else
mergedGrouping = '\0';
final int mergedMinFrac = Math.min(this.minFractionDigits, other.minFractionDigits);
final int mergedMaxFrac = Math.max(this.maxFractionDigits, other.maxFractionDigits);
if (mergedGrouping != '\0' && mergedDecimal != '\0' && mergedGrouping == mergedDecimal)
mergedGrouping = '\0';
return new DeduceFormat(mergedForceSign, mergedGrouping, mergedDecimal, mergedMinFrac, mergedMaxFrac);
}
public DecimalFormat getDecimalFormat() {
final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
if (decimalSep != '\0')
symbols.setDecimalSeparator(decimalSep);
if (groupingSep != '\0')
symbols.setGroupingSeparator(groupingSep);
final StringBuilder pattern = new StringBuilder();
if (forceSign)
pattern.append("+");
if (groupingSep != '\0')
pattern.append("#,##0");
else
pattern.append("0");
if (minFractionDigits > 0) {
pattern.append(".");
for (int i = 0; i < minFractionDigits; i++)
pattern.append("0");
}
final DecimalFormat df = new DecimalFormat(pattern.toString(), symbols);
df.setGroupingUsed(groupingSep != '\0');
df.setMinimumFractionDigits(minFractionDigits);
df.setMaximumFractionDigits(maxFractionDigits);
return df;
}
static class CharCount {
char ch;
int count;
public void init(char newOne) {
ch = newOne;
count = 1;
}
}
public static DeduceFormat from(String number) {
final CharCount nonDigit1 = new CharCount();
final CharCount nonDigit2 = new CharCount();
char sign = '\0';
if (number.charAt(0) == '+' || number.charAt(0) == '-') {
sign = number.charAt(0);
number = number.substring(1);
}
int fractionDigits = 0;
for (int i = 0; i < number.length(); i++) {
final char ch = number.charAt(i);
if (Character.isDigit(ch)) {
if (nonDigit1.count > 0)
fractionDigits++;
continue;
}
if (nonDigit1.count == 0) {
nonDigit1.init(ch);
fractionDigits = 0;
} else if (nonDigit1.ch == ch) {
nonDigit1.count++;
} else if (nonDigit2.count == 0) {
nonDigit2.init(ch);
fractionDigits = 0;
} else if (nonDigit2.ch == ch) {
nonDigit2.count++;
} else
return null;
}
if (nonDigit1.count > 0 && nonDigit2.count > 0)
return new DeduceFormat(sign == '+', nonDigit1.ch, nonDigit2.ch, fractionDigits, fractionDigits);
return new DeduceFormat(sign == '+', '\0', nonDigit1.ch, fractionDigits, fractionDigits);
}
@Override
public String toString() {
if (minFractionDigits == maxFractionDigits)
return "DeduceFormat{" + "forceSign=" + forceSign + ", groupingSep="
+ (groupingSep == '\0' ? "none" : "'" + groupingSep + "'") + ", decimalSep="
+ (decimalSep == '\0' ? "none" : "'" + decimalSep + "'") + ", fractionDigits=" + minFractionDigits
+ '}';
return "DeduceFormat{" + "forceSign=" + forceSign + ", groupingSep="
+ (groupingSep == '\0' ? "none" : "'" + groupingSep + "'") + ", decimalSep="
+ (decimalSep == '\0' ? "none" : "'" + decimalSep + "'") + ", minFractionDigits=" + minFractionDigits
+ ", maxFractionDigits=" + maxFractionDigits + '}';
}
}