File: NumberUtils.java

package info (click to toggle)
gpsprune 26.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,824 kB
  • sloc: java: 52,154; sh: 25; makefile: 21; python: 15
file content (173 lines) | stat: -rw-r--r-- 5,085 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package tim.prune.data;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

/**
 * Abstract class to offer general number manipulation functions
 */
public abstract class NumberUtils
{
	/** Locale-specific number formatter */
	private static final NumberFormat LOCAL_FORMAT = NumberFormat.getNumberInstance();

	/** UK-specific number formatter object to avoid lots of instantiations */
	private static final NumberFormat UK_FORMAT = NumberFormat.getNumberInstance(Locale.UK);
	// Select the UK locale for this formatter so that decimal point is always used (not comma)
	static {
		if (UK_FORMAT instanceof DecimalFormat) ((DecimalFormat) UK_FORMAT).applyPattern("0.000");
	}

	/**
	 * Format the given number in UK format (decimal point) to the given number of decimal places
	 * @param inNumber double number to format
	 * @param inDecimalPlaces number of decimal places
	 */
	public static String formatNumberUk(double inNumber, int inDecimalPlaces)
	{
		UK_FORMAT.setMaximumFractionDigits(inDecimalPlaces);
		UK_FORMAT.setMinimumFractionDigits(inDecimalPlaces);
		UK_FORMAT.setRoundingMode(RoundingMode.HALF_UP);
		return UK_FORMAT.format(inNumber);
	}

	/**
	 * Format the given number in the local format to the given number of decimal places
	 * @param inNumber double number to format
	 * @param inDecimalPlaces number of decimal places
	 */
	public static String formatNumberLocal(double inNumber, int inDecimalPlaces)
	{
		final int numDecimals = (inDecimalPlaces < 0 ? 3 : inDecimalPlaces);
		LOCAL_FORMAT.setMaximumFractionDigits(numDecimals);
		LOCAL_FORMAT.setMinimumFractionDigits(numDecimals);
		LOCAL_FORMAT.setRoundingMode(RoundingMode.HALF_UP);
		return LOCAL_FORMAT.format(inNumber);
	}

	/**
	 * @return the number of decimal places in the given string
	 * or -1 if the string doesn't represent a number
	 */
	public static int numberOfDecimalPlaces(String inString)
	{
		String value = (inString == null ? "" : inString.trim());
		int cPos = value.length() - 1;
		int digits = 0;
		boolean hasAnyDigits = false;
		while (cPos >= 0)
		{
			char c = value.charAt(cPos);
			if (!Character.isDigit(c))
			{
				if (c == '.' || c == ',') {
					return (hasAnyDigits || digits == 0) ? digits : -1;
				}
				return hasAnyDigits ? 0 : -1;
			}
			hasAnyDigits = true;
			cPos--;
			digits++;
		}
		return hasAnyDigits ? 0 : -1;
	}

	/**
	 * Format the given number in the local format to match the number of decimal places
	 * @param inNumber double number to format
	 * @param inPattern example string showing decimals
	 */
	public static String formatNumberLocalToMatch(double inNumber, String inPattern) {
		return formatNumberLocal(inNumber, numberOfDecimalPlaces(inPattern));
	}

	/**
	 * @param inValue string value, can be null or empty
	 * @return value extracted using either java formatting or locale formatting
	 */
	static Double parseDoubleUsingLocale(String inValue)
	{
		final String trimmedValue = (inValue == null ? "" : inValue.trim());
		if (trimmedValue.isEmpty()) {
			return null;
		}
		// We have some contents, so try parsing using the regular java formatting (decimal dot)
		try {
			return Double.parseDouble(trimmedValue);
		}
		catch (NumberFormatException ignored) {
		}

		// That threw an exception, so try with the system's locale instead (for example, using decimal comma)
		if (isLocalDecimal(inValue))
		{
			try
			{
				NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
				return nf.parse(trimmedValue).doubleValue();
			}
			catch (ParseException ignored) {
			}
		}
		// Neither worked
		return null;
	}

	/** @return true if the given string looks like a local decimal value */
	private static boolean isLocalDecimal(String inValue)
	{
		if (inValue == null || inValue.isEmpty()) {
			return false;
		}
		String allowedChars = "-0123456789";
		NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
		if (nf instanceof DecimalFormat) {
			allowedChars += ((DecimalFormat) nf).getDecimalFormatSymbols().getDecimalSeparator();
		}
		for (int i=0; i<inValue.length(); i++)
		{
			if (allowedChars.indexOf(inValue.charAt(i)) < 0) {
				return false; // another character found
			}
		}
		// only contains allowed characters
		return true;
	}

	/** @return String to use between numbers, depending on the decimal character */
	public static String getValueSeparator()
	{
		NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
		if (nf instanceof DecimalFormat)
		{
			char decimalChar = ((DecimalFormat) nf).getDecimalFormatSymbols().getDecimalSeparator();
			if (decimalChar == ',') {
				return "; ";
			}
		}
		return ", ";
	}

	public static int getIntOrZero(String inString)
	{
		try {
			return Integer.parseInt(inString);
		}
		catch (NumberFormatException ignored) {
			return 0;
		}
	}

	public static double getDoubleOrZero(String inString)
	{
		try {
			return Double.parseDouble(inString);
		}
		catch (NumberFormatException | NullPointerException ignored) {
			return 0.0;
		}
	}
}