1 package io.jawk.jrt;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * Jawk
6 * ჻჻჻჻჻჻
7 * Copyright (C) 2006 - 2026 MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 import java.math.BigDecimal;
26
27 /**
28 * An input-derived scalar: text that may also act as a number, following
29 * POSIX "numeric string" (strnum) semantics. Input fields, {@code getline}
30 * results, {@code split()} pieces, and similar input-originated values are
31 * represented as instances of this class so comparisons and gawk's
32 * {@code typeof()} can distinguish them from plain string constants.
33 */
34 public final class StrNum {
35
36 private final String value;
37 private final char decimalSeparator;
38 private Boolean numeric;
39 private Double numericValue;
40
41 StrNum(String value) {
42 this(value, '.');
43 }
44
45 StrNum(String value, char decimalSeparator) {
46 this.value = value == null ? "" : value;
47 this.decimalSeparator = decimalSeparator;
48 }
49
50 /**
51 * Returns whether this scalar's text parses as an AWK number, making it a
52 * strnum.
53 *
54 * @return {@code true} when the text is a valid AWK number
55 */
56 public boolean isNumber() {
57 if (numeric == null) {
58 numeric = Boolean.valueOf(JRT.isParseableNumber(value, decimalSeparator));
59 }
60 return numeric.booleanValue();
61 }
62
63 /**
64 * Returns this scalar's numeric value.
65 *
66 * @return the parsed numeric value
67 */
68 public double doubleValue() {
69 if (numericValue == null) {
70 numericValue = Double.valueOf(parseDoubleValue());
71 }
72 return numericValue.doubleValue();
73 }
74
75 private double parseDoubleValue() {
76 String normalizedValue = JRT.normalizeNumberForComparison(value, decimalSeparator);
77 try {
78 return Double.parseDouble(normalizedValue);
79 } catch (NumberFormatException nfe) {
80 return new BigDecimal(normalizedValue).doubleValue();
81 }
82 }
83
84 @Override
85 public String toString() {
86 return value;
87 }
88 }