From 7e01bae3cd7b64686ee25d11172a8051b37eb799 Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Mon, 4 Feb 2019 02:37:47 +0000 Subject: [PATCH] handle number formats with no required digits git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/jdk8@1273 f203690c-595d-4dc9-a70b-905162fa7fd2 --- .../jackcess/impl/expr/FormatUtil.java | 69 +++++++++++++++---- .../impl/expr/DefaultFunctionsTest.java | 17 +++-- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java index 7f23b4e..6dfc2e3 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java @@ -169,6 +169,7 @@ public class FormatUtil private static final char EXP_e_CHAR = 'e'; private static final char PLUS_CHAR = '+'; private static final char MINUS_CHAR = '-'; + private static final char REQ_DIGIT_CHAR = '0'; private static final int NO_CHAR = -1; private static final byte FCT_UNKNOWN = 0; @@ -554,7 +555,8 @@ public class FormatUtil private static void addCustomGeneralFormat(String[] fmtStrs, int fmtIdx, StringBuilder sb) { - addCustomNumberFormat(fmtStrs, NO_EXP_TYPES, NO_FMT_TYPES, fmtIdx, sb); + addCustomNumberFormat(fmtStrs, NO_EXP_TYPES, NO_FMT_TYPES, NO_FMT_TYPES, + fmtIdx, sb); } private static Fmt parseCustomDateFormat(ExprBuf buf, Args args) { @@ -735,6 +737,7 @@ public class FormatUtil NumberFormatter.NotationType[] expTypes = new NumberFormatter.NotationType[NUM_NF_FMTS]; boolean[] hasFmts = new boolean[NUM_NF_FMTS]; + boolean[] hasReqDigit = new boolean[NUM_NF_FMTS]; BUF_LOOP: while(buf.hasNext()) { @@ -773,7 +776,8 @@ public class FormatUtil break BUF_LOOP; } flushPendingNumberLiteral(pendingLiteral, sb); - addCustomNumberFormat(fmtStrs, expTypes, hasFmts, fmtIdx++, sb); + addCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + fmtIdx++, sb); break; default: pendingLiteral.append(c); @@ -808,6 +812,11 @@ public class FormatUtil pendingLiteral.append(c); } break; + case REQ_DIGIT_CHAR: + hasReqDigit[fmtIdx] = true; + flushPendingNumberLiteral(pendingLiteral, sb); + sb.append(c); + break; default: // most number format chars pass straight through flushPendingNumberLiteral(pendingLiteral, sb); @@ -822,19 +831,24 @@ public class FormatUtil // fill in remaining formats while(fmtIdx < NUM_NF_FMTS) { flushPendingNumberLiteral(pendingLiteral, sb); - addCustomNumberFormat(fmtStrs, expTypes, hasFmts, fmtIdx++, sb); + addCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + fmtIdx++, sb); } return new CustomNumberFmt( - createCustomNumberFormat(fmtStrs, expTypes, hasFmts, NF_POS_IDX, args), - createCustomNumberFormat(fmtStrs, expTypes, hasFmts, NF_NEG_IDX, args), - createCustomNumberFormat(fmtStrs, expTypes, hasFmts, NF_ZERO_IDX, args), - createCustomNumberFormat(fmtStrs, expTypes, hasFmts, NF_NULL_IDX, args)); + createCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + NF_POS_IDX, false, args, buf), + createCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + NF_NEG_IDX, false, args, buf), + createCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + NF_ZERO_IDX, true, args, buf), + createCustomNumberFormat(fmtStrs, expTypes, hasFmts, hasReqDigit, + NF_NULL_IDX, true, args, buf)); } private static void addCustomNumberFormat( String[] fmtStrs, NumberFormatter.NotationType[] expTypes, - boolean[] hasFmts, int fmtIdx, StringBuilder sb) + boolean[] hasFmts, boolean[] hasReqDigit, int fmtIdx, StringBuilder sb) { if(sb.length() == 0) { // do special empty format handling on a per-format-type basis @@ -844,12 +858,14 @@ public class FormatUtil sb.append('-').append(fmtStrs[NF_POS_IDX]); expTypes[NF_NEG_IDX] = expTypes[NF_POS_IDX]; hasFmts[NF_NEG_IDX] = hasFmts[NF_POS_IDX]; + hasReqDigit[NF_NEG_IDX] = hasReqDigit[NF_POS_IDX]; break; case NF_ZERO_IDX: // re-use "pos" format sb.append(fmtStrs[NF_POS_IDX]); expTypes[NF_ZERO_IDX] = expTypes[NF_POS_IDX]; hasFmts[NF_ZERO_IDX] = hasFmts[NF_POS_IDX]; + hasReqDigit[NF_ZERO_IDX] = hasReqDigit[NF_POS_IDX]; break; default: // use empty string result @@ -892,14 +908,15 @@ public class FormatUtil private static BDFormat createCustomNumberFormat( String[] fmtStrs, NumberFormatter.NotationType[] expTypes, - boolean[] hasFmts, int fmtIdx, Args args) { + boolean[] hasFmts, boolean[] hasReqDigit, int fmtIdx, + boolean isZeroFmt, Args args, ExprBuf buf) { String fmtStr = fmtStrs[fmtIdx]; if(!hasFmts[fmtIdx]) { // convert the literal string to a dummy number format if(fmtStr.length() > 0) { // strip quoting - StringBuilder sb = new StringBuilder(fmtStr) + StringBuilder sb = buf.getScratchBuffer().append(fmtStr) .deleteCharAt(fmtStr.length() - 1) .deleteCharAt(0); if(sb.length() > 0) { @@ -927,8 +944,36 @@ public class FormatUtil } if(expType != null) { - return new BaseBDFormat( - new NumberFormatter.ScientificFormat(df, expType)); + NumberFormat nf = new NumberFormatter.ScientificFormat(df, expType); + if(isZeroFmt) { + return new LiteralBDFormat(nf.format(BigDecimal.ZERO)); + } + return new BaseBDFormat(nf); + } + + if(!hasReqDigit[fmtIdx]) { + // java likes to force extra 0's while access doesn't + df.setMinimumIntegerDigits(0); + } + + if(isZeroFmt) { + + String zeroVal = df.format(BigDecimal.ZERO); + if(!hasReqDigit[fmtIdx]) { + // java forces a 0 but access doesn't. delete any 0 chars which were + // inserted by the java format + int prefLen = df.getPositivePrefix().length(); + int len = zeroVal.length() - df.getPositiveSuffix().length(); + StringBuilder sb = buf.getScratchBuffer().append(zeroVal); + for(int i = len - 1; i >= prefLen; --i) { + if(sb.charAt(i) == '0') { + sb.deleteCharAt(i); + } + } + zeroVal = sb.toString(); + } + + return new LiteralBDFormat(zeroVal); } return new DecimalBDFormat(df); diff --git a/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java b/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java index b25f150..dc4cabb 100644 --- a/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java +++ b/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java @@ -472,11 +472,20 @@ public class DefaultFunctionsTest extends TestCase assertEvalFormat("'#'", "13", "13", - "0", "0.003", + "", "0.003", "-45", "-45", - "0", "-0.003" - // FIXME - // "", "0" + "", "-0.003", + "", "0" + ); + + assertEvalFormat("'\\0\\[#.#\\]\\0'", + "0[13.]0", "13", + "0[.]0", "0.003", + "0[.3]0", "0.3", + "-0[45.]0", "-45", + "0[.]0", "-0.003", + "-0[.3]0", "-0.3", + "0[.]0", "0" ); assertEvalFormat("\"#;n'g;'\"", -- 2.39.5