Scribunto: Trim zeroes when stringifying Doubles [#697]

staging
gnosygnu 4 years ago
parent f122a8d8a3
commit bdae819908

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -14,6 +14,7 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx;
public class Double_ {
public static final String Cls_val_name = "double";
public static final Class<?> Cls_ref_type = Double.class;
@ -42,7 +43,9 @@ public class Double_ {
int v_as_int = (int)v;
return v == v_as_int
? Int_.To_str(v_as_int) // convert to int, and call print String to eliminate any trailing decimal places
: Float_.To_str((float)v); // calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d; DATE:2014-07-29
// DATE:2014-07-29; calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d
// DATE:2020-08-12; calling ToStrByPrintF b/c better at removing trailing 0s; ISSUE#:697;
: gplx.objects.primitives.Double_.ToStrByPrintF(v);
}
public static int Compare(double lhs, double rhs) {
if (lhs == rhs) return CompareAble_.Same;

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,11 +13,27 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
import org.junit.*;
import gplx.langs.jsons.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.langs.numbers.*;
import gplx.xowa.xtns.cldrs.*;
package gplx.xowa.xtns.scribunto.libs;
import gplx.Bry_;
import gplx.DateAdp_;
import gplx.Datetime_now;
import gplx.Gfo_invk_;
import gplx.Io_mgr;
import gplx.Keyval;
import gplx.Keyval_;
import gplx.Object_;
import gplx.String_;
import gplx.langs.jsons.Json_doc;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.langs.Xol_lang_itm;
import gplx.xowa.langs.msgs.Xol_msg_mgr;
import gplx.xowa.xtns.cldrs.Cldr_name_loader_fxt;
import gplx.xowa.xtns.scribunto.Scrib_invoke_func_fxt;
import gplx.xowa.xtns.scribunto.Scrib_lib;
import org.junit.Before;
import org.junit.Test;
public class Scrib_lib_language_tst {
@Before public void init() {
fxt.Clear_for_lib();
@ -98,6 +114,7 @@ public class Scrib_lib_language_tst {
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234", Keyval_.Ary(Keyval_.new_("noCommafy", true))) , "1234"); // noCommafy.y
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234", Keyval_.Ary(Keyval_.new_("noCommafy", false))) , "1,234"); // noCommafy.n
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234", Keyval_.Ary(Keyval_.new_("noCommafy", "y"))) , "1234"); // noCommafy."y"; ISSUE#:372 DATE:2019-03-02
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", 768d / 10000000d) , "7.68E-5"); // ensure "e-05" -> "E-5" ISSUE#:697; DATE:2020-08-12
}
@Test public void FormatDate() {
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d", "2013-03-17", false), "2013-03-17");

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,8 +13,100 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.objects.primitives; import gplx.*; import gplx.objects.*;
package gplx.objects.primitives;
public class Double_ {
public static final String Cls_val_name = "double";
public static final Class<?> Cls_ref_type = Double.class;
public static final Class<?> Cls_ref_type = Double.class;
public static String ToStrByPrintF(double val) {
// call sprintf-like format; EX:"sprintf((s), "%.14g", (n));"
return TrimZeroes(String.format("%.14g", val));
}
public static String TrimZeroes(String valStr) { // TEST
// NOTE:this function was originally in LuaDouble; it was refactored for clarity, and also to handle trimming zeroes from exponent; EX:"e-05" ISSUE#:697; DATE:2020-08-12
int valStrLen = valStr.length();
boolean startTrimming = true; // will be set to true at end of string (12.00), or before "e" (1.00e5)
boolean trimmingZeroes = false;
int trimIdx = -1;
int expIdx = -1;
// read backwards from end of string
for (int i = valStrLen - 1; i > -1; i--) {
switch (valStr.charAt(i)) {
case '0':
// if startTrimming is true, then enable trimmingZeroes; should only occur twice; (1) end of string ("12.00"); (2) before "e" ("1.00e5")
if (startTrimming) {
startTrimming = false;
trimmingZeroes = true;
}
// if trimmingZeroes, set trimIdx just before this `0`
if (trimmingZeroes)
trimIdx = i;
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
// disable trimmingZeroes; EX: "12.30"
trimmingZeroes = false;
startTrimming = false; // mark startTrimming false else will gobble up zeroes before numbers; EX: "0.00001" x> "0.1"; ISSUE#:697; DATE:2020-08-11
break;
case '-': // ignore scientific notation or negative sign; EX: "5.0e-17", "-1"
break;
case 'e': // scientific notation; reset startTrimming; EX: 5.0000000000000e-17
expIdx = i;
startTrimming = true;
break;
case '.':
// if still trimmingZeroes, and reached decimalPoint, then update trimIdx to truncate decimalPoint also; EX: "123.0000" -> "123" x> "123."
if (trimmingZeroes)
trimIdx = i;
// trimIdx has been set
if (trimIdx != -1) {
if (expIdx == -1) { // decimal; EX: "12.00"
valStr = valStr.substring(0, trimIdx);
}
else { // exponent; "1.00e5"
// get exponent portion; EX: "e-05"
String expStr = valStr.substring(expIdx, valStrLen);
int expStrLen = expStr.length();
// set expSymIdx to be after "e" or "e-"
int expSymIdx = 1; // skip the "e"
if (expSymIdx < expStrLen && !Character.isDigit(expStr.charAt(expSymIdx))) { // skip "-" if it's there
expSymIdx++;
}
// exponent can have 0s; skip them; EX: 1.1e-05
int expNumIdx = expSymIdx;
for (int j = expNumIdx; j < expStrLen; j++) {
if (expStr.charAt(j) == '0') { // skip zeroes
expNumIdx++;
}
else {
break;
}
}
// now stitch it together
valStr = valStr.substring(0, trimIdx)
+ expStr.substring(0, expSymIdx) // add "e-"
+ expStr.substring(expNumIdx); // add numbers with any leading zeroes trimmed
}
}
// NOTE: "e" needs to be uppercased to "E"; PAGE:en.w:List_of_countries_and_dependencies_by_population
if (expIdx != -1) {
valStr = valStr.toUpperCase();
}
i = -1; // no more trimming needed before decimalPoint; stop looping
break;
default: // anything else; stop looping
i = -1;
break;
}
}
return valStr;
}
}

@ -0,0 +1,51 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.objects.primitives;
import gplx.tests.Gftest_fxt;
import org.junit.Test;
public class Double_Test {
private final Double_Tstr tstr = new Double_Tstr();
@Test
public void TrimZeroes() {
tstr.Test_TrimZeroes("12.100" , "12.1");
tstr.Test_TrimZeroes("12.000" , "12");
tstr.Test_TrimZeroes("12.001" , "12.001");
tstr.Test_TrimZeroes("1020.00" , "1020");
tstr.Test_TrimZeroes("1020.00" , "1020");
tstr.Test_TrimZeroes("1.200e5" , "1.2E5");
tstr.Test_TrimZeroes("1.200e-05" , "1.2E-5");
}
@Test
public void ToStrByPrintF() {
tstr.Test_ToStrByPrintF(1d / 2d , "0.5"); // fails with 0.50000000000000
tstr.Test_ToStrByPrintF(5d / 100000000000000000d, "5E-17"); // fails with 5.0000000000000e-17
tstr.Test_ToStrByPrintF(7538000d / 7773352000d , "0.00096972322879499"); // fails with 0; ISSUE#:697; DATE:2020-08-11
tstr.Test_ToStrByPrintF(56225d / 7776747000d , "7.2298867379895E-06"); // fails with 0; ISSUE#:697; DATE:2020-08-11
tstr.Test_ToStrByPrintF(35746d / 7805411000d , "4.5796435319037E-06"); // fails with 0; ISSUE#:697; DATE:2020-08-11
}
}
class Double_Tstr {
public void Test_ToStrByPrintF(double v, String expd) {
Gftest_fxt.Eq__str(expd, Double_.ToStrByPrintF(v));
}
public void Test_TrimZeroes(String val, String expd) {
Gftest_fxt.Eq__str(expd, Double_.TrimZeroes(val));
}
}
Loading…
Cancel
Save