You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by ja...@apache.org on 2018/07/09 14:52:46 UTC

[incubator-daffodil] 09/13: Addressed issues brought up in code review

This is an automated email from the ASF dual-hosted git repository.

jadams pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git

commit 59008f6bb9d5436f07cea2ac2dcebc73c42c5c0b
Author: Josh Adams <ja...@tresys.com>
AuthorDate: Mon Jun 18 16:26:11 2018 -0400

    Addressed issues brought up in code review
    
     - Made conversion functions much more effecient by converting only the
     single character that is overpunched instead of iterating over and
     running the conversion on all digits in the number
     - Added regex to further validate the number pattern being passed in
     works with zoned numbers
     - Got rid of all the ConvertZoned*Helper classes and used the
     existing ConvertText*Helper classes instead
     - Realized that with a very small change to the existing
     NumberFormatFactory I could use that instead of making my own almost
     identical version for zoned numbers
    
    DAFFODIL-1738
---
 .../grammar/primitives/PrimitivesTextNumber.scala  |   4 +-
 .../grammar/primitives/PrimitivesZoned.scala       |  99 +++---
 .../org/apache/daffodil/util/DecimalUtils.scala    | 199 ++++++------
 .../apache/daffodil/util/TestDecimalUtils.scala    | 261 ++++++++--------
 .../unparsers/ConvertZonedNumberUnparser.scala     |  10 +-
 .../processors/parsers/PrimitivesTextNumber1.scala |  34 +-
 .../processors/parsers/ZonedTextParsers.scala      | 347 ++-------------------
 .../org/apache/daffodil/section13/zoned/zoned.tdml |  30 +-
 .../daffodil/section13/zoned/TestZoned.scala       |   2 +
 9 files changed, 370 insertions(+), 616 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesTextNumber.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesTextNumber.scala
index 7907797..84a9f1c 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesTextNumber.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesTextNumber.scala
@@ -132,7 +132,7 @@ abstract class ConvertTextNumberPrim[S](e: ElementBase)
       new NumberFormatFactoryStatic[S](e.termRuntimeData, h,
         decSep,
         groupSep,
-        e.textStandardExponentRepEv,
+        One(e.textStandardExponentRepEv),
         infRep,
         nanRep,
         e.textNumberCheckPolicy,
@@ -144,7 +144,7 @@ abstract class ConvertTextNumberPrim[S](e: ElementBase)
       new NumberFormatFactoryDynamic[S](e.termRuntimeData, h,
         decSep,
         groupSep,
-        e.textStandardExponentRepEv,
+        One(e.textStandardExponentRepEv),
         infRep,
         nanRep,
         e.textNumberCheckPolicy,
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesZoned.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesZoned.scala
index 433f093..5ede415 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesZoned.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesZoned.scala
@@ -25,33 +25,36 @@ import com.ibm.icu.text.DecimalFormat
 import org.apache.daffodil.processors.unparsers.Unparser
 import org.apache.daffodil.processors.unparsers.ConvertZonedNumberUnparser
 import org.apache.daffodil.processors.unparsers.ConvertZonedCombinatorUnparser
-import java.math.{ BigDecimal => JBigDecimal, BigInteger => JBigInt }
-import org.apache.daffodil.processors.parsers.ConvertZonedByteParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedCombinatorParser
-import org.apache.daffodil.processors.parsers.ConvertZonedDecimalParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedIntParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedIntegerParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedLongParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedNonNegativeIntegerParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedNumberParser
-import org.apache.daffodil.processors.parsers.ConvertZonedNumberParserUnparserHelperBase
-import org.apache.daffodil.processors.parsers.ConvertZonedShortParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedUnsignedByteParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedUnsignedLongParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ConvertZonedUnsignedShortParserUnparserHelper
-import org.apache.daffodil.processors.parsers.ZonedFormatFactoryBase
-import org.apache.daffodil.processors.parsers.ZonedFormatFactoryStatic
-import org.apache.daffodil.processors.parsers.ConvertZonedUnsignedIntParserUnparserHelper
 import org.apache.daffodil.processors.parsers.Parser
+import org.apache.daffodil.processors.parsers.ConvertZonedNumberParser
+import org.apache.daffodil.processors.parsers.ConvertZonedCombinatorParser
+import org.apache.daffodil.processors.parsers.ConvertTextByteParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextDecimalParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextIntParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextIntegerParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextLongParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextNonNegativeIntegerParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextNumberParserUnparserHelperBase
+import org.apache.daffodil.processors.parsers.ConvertTextShortParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextUnsignedByteParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextUnsignedLongParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextUnsignedShortParserUnparserHelper
+import org.apache.daffodil.processors.parsers.ConvertTextUnsignedIntParserUnparserHelper
+import org.apache.daffodil.processors.parsers.NumberFormatFactoryBase
+import org.apache.daffodil.processors.parsers.NumberFormatFactoryStatic
 import org.apache.daffodil.schema.annotation.props.gen.TextNumberCheckPolicy
 import org.apache.daffodil.schema.annotation.props.gen.TextNumberRounding
+import org.apache.daffodil.util.Maybe
 import org.apache.daffodil.util.Maybe._
 import org.apache.daffodil.util.MaybeDouble
 
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+
 case class ConvertZonedCombinator(e: ElementBase, value: Gram, converter: Gram)
   extends Terminal(e, !(value.isEmpty || converter.isEmpty)) {
 
-  lazy val parser = new ConvertZonedCombinatorParser(e.termRuntimeData, value.parser, converter.parser)
+  override lazy val parser = new ConvertZonedCombinatorParser(e.termRuntimeData, value.parser, converter.parser)
 
   override lazy val unparser = new ConvertZonedCombinatorUnparser(e.termRuntimeData, value.unparser, converter.unparser)
 }
@@ -59,9 +62,9 @@ case class ConvertZonedCombinator(e: ElementBase, value: Gram, converter: Gram)
 abstract class ConvertZonedNumberPrim[S](e: ElementBase)
   extends Terminal(e, true) {
 
-  def helper: ConvertZonedNumberParserUnparserHelperBase[S]
+  def helper: ConvertTextNumberParserUnparserHelperBase[S]
 
-  def numFormatFactory: ZonedFormatFactoryBase[S] = {
+  def numFormatFactory: NumberFormatFactoryBase[S] = {
     val h = helper
 
     val pattern = {
@@ -71,6 +74,7 @@ abstract class ConvertZonedNumberPrim[S](e: ElementBase)
       val patternNoEscapedTicks = noEscapedTicksRegex.replaceAllIn(p, "")
       val noQuotedRegex = """'[^']+'""".r
       val patternNoQuoted = noQuotedRegex.replaceAllIn(patternNoEscapedTicks, "")
+      val zonedPatternRegex = "\\+?#*[0-9]+\\+?".r
 
       if (patternNoQuoted.contains("V")) {
         e.notYetImplemented("textNumberPattern with V symbol")
@@ -92,19 +96,25 @@ abstract class ConvertZonedNumberPrim[S](e: ElementBase)
         case PrimType.Double | PrimType.Float => e.SDE("textZonedFormat='zoned' does not support Doubles/Floats")
         case PrimType.UnsignedLong | PrimType.UnsignedInt | PrimType.UnsignedShort | PrimType.UnsignedByte => {
           if (e.textNumberCheckPolicy == TextNumberCheckPolicy.Lax) {
-            if ((patternNoQuoted.charAt(0) != '+') && (patternNoQuoted.charAt(patternNoQuoted.length - 1) != '+'))
+            if ((patternNoQuoted(0) != '+') && (patternNoQuoted(patternNoQuoted.length - 1) != '+'))
               e.SDE("textNumberPattern must have '+' at the beginning or the end of the pattern when textZonedFormat='zoned' and textNumberPolicy='lax' for unsigned numbers")
           }
         }
         case _ => {
-          if ((patternNoQuoted.charAt(0) != '+') && (patternNoQuoted.charAt(patternNoQuoted.length - 1) != '+'))
+          if ((patternNoQuoted(0) != '+') && (patternNoQuoted(patternNoQuoted.length - 1) != '+'))
             e.SDE("textNumberPattern must have '+' at the beginning or the end of the pattern when textZonedFormat='zoned' for signed numbers")
         }
       }
 
+      if ((patternNoQuoted(0) == '+') && (patternNoQuoted(patternNoQuoted.length - 1) == '+'))
+        e.SDE("The textNumberPattern may either begin or end with a '+', not both.")
+
+      if (!zonedPatternRegex.pattern.matcher(patternNoQuoted).matches)
+        e.SDE("Invalid characters used in textNubmerPattern for zoned number. Only the following characters may be used with zoned numbers: '+', 'V', 'P', '0-9', and '#'")
+
       // Load the pattern to make sure it is valid
       try {
-        new DecimalFormat(p)
+        new DecimalFormat(p.replace("+", ""))
       } catch {
         case ex: IllegalArgumentException => e.SDE("Invalid textNumberPattern: " + ex.getMessage())
       }
@@ -112,67 +122,80 @@ abstract class ConvertZonedNumberPrim[S](e: ElementBase)
       p
     }
 
-    val (roundingIncrement: MaybeDouble, roundingMode) =
+    /* Need to remove the '+' from the number pattern as '+' is only
+    *  used to indicate which digit of the number is overpunched when
+    *  dealing with zoned decimal formats. If the '+' is not removed
+    *  DecimalFormat will attempt to use it as an indicator for exponent
+    *  numbers, which will most likely not match the zoned number being
+    *  parsed */
+    val zonedPattern = pattern.replace("+", "")
+
+    val (roundingIncrement, roundingMode) =
       e.textNumberRounding match {
         case TextNumberRounding.Explicit => (MaybeDouble(e.textNumberRoundingIncrement), One(e.textNumberRoundingMode))
         case TextNumberRounding.Pattern => (MaybeDouble.Nope, Nope)
       }
 
-    val nff = new ZonedFormatFactoryStatic[S](
+    val nff = new NumberFormatFactoryStatic[S](
       e.termRuntimeData, h,
+      Maybe.Nope,
+      Maybe.Nope,
+      Maybe.Nope,
+      Maybe.Nope,
+      Maybe.Nope,
       e.textNumberCheckPolicy,
-      pattern,
+      zonedPattern,
       e.textNumberRounding,
       roundingMode,
       roundingIncrement)
     nff
   }
 
-  lazy val parser: Parser = new ConvertZonedNumberParser[S](helper, numFormatFactory, e.textZonedSignStyle, e.elementRuntimeData)
+  lazy val parser: Parser = new ConvertZonedNumberParser[S](helper, e.textNumberPattern, numFormatFactory, e.textZonedSignStyle, e.elementRuntimeData)
 
   override lazy val unparser: Unparser = new ConvertZonedNumberUnparser[S](helper, e.textNumberPattern, e.textZonedSignStyle, e.elementRuntimeData)
 }
 
 case class ConvertZonedIntegerPrim(e: ElementBase) extends ConvertZonedNumberPrim[JBigInt](e) {
-  val helper = new ConvertZonedIntegerParserUnparserHelper[JBigInt]()
+  val helper = new ConvertTextIntegerParserUnparserHelper[JBigInt](List(), false)
 }
 
 case class ConvertZonedDecimalPrim(e: ElementBase) extends ConvertZonedNumberPrim[JBigDecimal](e) {
-  val helper = new ConvertZonedDecimalParserUnparserHelper[JBigDecimal]()
+  val helper = new ConvertTextDecimalParserUnparserHelper[JBigDecimal](List(), false)
 }
 
 case class ConvertZonedNonNegativeIntegerPrim(e: ElementBase) extends ConvertZonedNumberPrim[JBigInt](e) {
-  val helper = new ConvertZonedNonNegativeIntegerParserUnparserHelper[JBigDecimal]()
+  val helper = new ConvertTextNonNegativeIntegerParserUnparserHelper[JBigDecimal](List(), false)
 }
 
 case class ConvertZonedLongPrim(e: ElementBase) extends ConvertZonedNumberPrim[Long](e) {
-  val helper = new ConvertZonedLongParserUnparserHelper[Long]()
+  val helper = new ConvertTextLongParserUnparserHelper[Long](List(), false)
 }
 
 case class ConvertZonedIntPrim(e: ElementBase) extends ConvertZonedNumberPrim[Int](e) {
-  val helper = new ConvertZonedIntParserUnparserHelper[Int]()
+  val helper = new ConvertTextIntParserUnparserHelper[Int](List(), false)
 }
 
 case class ConvertZonedShortPrim(e: ElementBase) extends ConvertZonedNumberPrim[Short](e) {
-  val helper = new ConvertZonedShortParserUnparserHelper[Short]()
+  val helper = new ConvertTextShortParserUnparserHelper[Short](List(), false)
 }
 
 case class ConvertZonedBytePrim(e: ElementBase) extends ConvertZonedNumberPrim[Byte](e) {
-  val helper = new ConvertZonedByteParserUnparserHelper[Byte]()
+  val helper = new ConvertTextByteParserUnparserHelper[Byte](List(), false)
 }
 
 case class ConvertZonedUnsignedLongPrim(e: ElementBase) extends ConvertZonedNumberPrim[JBigInt](e) {
-  val helper = new ConvertZonedUnsignedLongParserUnparserHelper[JBigInt]()
+  val helper = new ConvertTextUnsignedLongParserUnparserHelper[JBigInt](List(), false)
 }
 
 case class ConvertZonedUnsignedIntPrim(e: ElementBase) extends ConvertZonedNumberPrim[Long](e) {
-  val helper = ConvertZonedUnsignedIntParserUnparserHelper[Long]()
+  val helper = ConvertTextUnsignedIntParserUnparserHelper[Long](List(), false)
 }
 
 case class ConvertZonedUnsignedShortPrim(e: ElementBase) extends ConvertZonedNumberPrim[Int](e) {
-  val helper = new ConvertZonedUnsignedShortParserUnparserHelper[Int]()
+  val helper = new ConvertTextUnsignedShortParserUnparserHelper[Int](List(), false)
 }
 
 case class ConvertZonedUnsignedBytePrim(e: ElementBase) extends ConvertZonedNumberPrim[Short](e) {
-  val helper = new ConvertZonedUnsignedByteParserUnparserHelper[Short]()
+  val helper = new ConvertTextUnsignedByteParserUnparserHelper[Short](List(), false)
 }
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/util/DecimalUtils.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/util/DecimalUtils.scala
index ce47c21..d9804a9 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/util/DecimalUtils.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/util/DecimalUtils.scala
@@ -18,7 +18,8 @@
 package org.apache.daffodil.util
 
 import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.schema.annotation.props.gen.{ BinaryNumberCheckPolicy, TextZonedSignStyle }
+import org.apache.daffodil.schema.annotation.props.gen.BinaryNumberCheckPolicy
+import org.apache.daffodil.schema.annotation.props.gen.TextZonedSignStyle
 
 import java.math.{ BigInteger => JBigInteger, BigDecimal => JBigDecimal }
 
@@ -111,7 +112,7 @@ object DecimalUtils {
   }
 
   def packedToBigDecimal(num: Array[Byte], scale: Int, signCodes: PackedSignCodes): JBigDecimal = {
-    return new JBigDecimal(packedToBigInteger(num, signCodes), scale)
+    new JBigDecimal(packedToBigInteger(num, signCodes), scale)
   }
 
   def packedFromBigInteger(bigInt: JBigInteger, minLengthInBits: Int, signCodes: PackedSignCodes): Array[Byte] = {
@@ -335,142 +336,154 @@ object DecimalUtils {
     outArray
   }
 
-  def convertFromAsciiStandard(digit: Int): (Int, Boolean) = {
-    if ((digit >= 48) && (digit <= 57)) // positive 0-9
-      return (digit - 48, false)
-    else if ((digit >= 112) && (digit <= 121)) // negative 0-9
-      return (digit - 112, true)
+  def convertFromAsciiStandard(digit: Char): (Int, Boolean) = {
+    if ((digit >= '0') && (digit <= '9')) // positive 0-9
+      (digit - 48, false)
+    else if ((digit >= 'p') && (digit <= 'y')) // negative 0-9
+      (digit - 112, true)
     else
       throw new NumberFormatException("Invalid zoned digit: " + digit)
   }
 
-  def convertToAsciiStandard(digit: Char, positive: Boolean, op: Boolean): Char = {
-    if (positive || !op)
-      return digit
+  def convertToAsciiStandard(digit: Char, positive: Boolean): Char = {
+    if (positive)
+      digit
     else
-      return (digit + 64).asInstanceOf[Char]
+      (digit + 64).asInstanceOf[Char]
   }
 
-  def convertFromAsciiTranslatedEBCDIC(digit: Int): (Int, Boolean) = {
-    if (digit == 123)
-      return (0, false)
-    else if (digit == 125)
-      return (0, true)
-    else if ((digit >= 65) && (digit <= 73)) // positive 1-9
-      return (digit - 64, false)
-    else if ((digit >= 74) && (digit <= 82)) // negative 1-9
-      return (digit - 73, true)
-    else if ((digit >= 48) && (digit <= 57))
-      return (digit - 48, false) // non-overpunched digit
+  def convertFromAsciiTranslatedEBCDIC(digit: Char): (Int, Boolean) = {
+    if (digit == '{')
+      (0, false)
+    else if (digit == '}')
+      (0, true)
+    else if ((digit >= 'A') && (digit <= 'I')) // positive 1-9
+      (digit - 64, false)
+    else if ((digit >= 'J') && (digit <= 'R')) // negative 1-9
+      (digit - 73, true)
+    else if ((digit >= '0') && (digit <= '9'))
+      (digit - 48, false) // non-overpunched digit
     else
       throw new NumberFormatException("Invalid zoned digit: " + digit)
   }
 
-  def convertToAsciiTranslatedEBCDIC(digit: Char, positive: Boolean, op: Boolean): Char = {
-    val result = (positive, op) match {
-      case (true, true) => { // Overpunch character with positive sign
-        if (digit == '0')
-          123
-        else
-          digit + 16
-      }
-      case (false, true) => { // Overpunch character with negative sign
-        if (digit == '0')
-          125
-        else
-          digit + 25
-      }
-      case _ => digit
+  def convertToAsciiTranslatedEBCDIC(digit: Char, positive: Boolean): Char = {
+    if (positive) {
+      if (digit == '0')
+        '{'
+      else
+        (digit + 16).asInstanceOf[Char]
+    } else {
+      if (digit == '0')
+        '}'
+      else
+        (digit + 25).asInstanceOf[Char]
     }
-
-    return result.asInstanceOf[Char]
   }
 
-  def convertFromAsciiCARealiaModified(digit: Int): (Int, Boolean) = {
-    if ((digit >= 48) && (digit <= 57)) // positive 0-9
-      return (digit - 48, false)
-    else if ((digit >= 32) && (digit <= 41)) // negative 0-9
-      return (digit - 32, true)
+  def convertFromAsciiCARealiaModified(digit: Char): (Int, Boolean) = {
+    if ((digit >= '0') && (digit <= '9')) // positive 0-9
+      (digit - 48, false)
+    else if ((digit >= ' ') && (digit <= ')')) // negative 0-9
+      (digit - 32, true)
     else
       throw new NumberFormatException("Invalid zoned digit: " + digit)
   }
 
-  def convertToAsciiCARealiaModified(digit: Char, positive: Boolean, op: Boolean): Char = {
-    if (positive || !op)
-      return digit
+  def convertToAsciiCARealiaModified(digit: Char, positive: Boolean): Char = {
+    if (positive)
+      digit
     else
-      return (digit - 16).asInstanceOf[Char]
+      (digit - 16).asInstanceOf[Char]
   }
 
-  def convertFromAsciiTandemModified(digit: Int): (Int, Boolean) = {
-    if ((digit >= 48) && (digit <= 57)) // positive 0-9
-      return (digit - 48, false)
+  def convertFromAsciiTandemModified(digit: Char): (Int, Boolean) = {
+    if ((digit >= '0') && (digit <= '9')) // positive 0-9
+      (digit - 48, false)
     else if ((digit >= 128) && (digit <= 137)) // negative 0-9
-      return (digit - 128, true)
+      (digit - 128, true)
     else
       throw new NumberFormatException("Invalid zoned digit: " + digit)
   }
 
-  def convertToAsciiTandemModified(digit: Char, positive: Boolean, op: Boolean): Char = {
-    if (positive || !op)
-      return digit
+  def convertToAsciiTandemModified(digit: Char, positive: Boolean): Char = {
+    if (positive)
+      digit
     else
-      return (digit + 80).asInstanceOf[Char]
+      (digit + 80).asInstanceOf[Char]
   }
 
-  def zonedToNumber(num: String, zonedStyle: TextZonedSignStyle): String = {
-    val decodedValue = new StringBuilder()
-    var negative = false
+  object OverpunchLocation extends Enumeration {
+    type OverpunchLocation = Value
+    val Start, End, None = Value
+  }
 
-    for (char <- num.chars().toArray) {
-      val (digit, opneg) = zonedStyle match {
-        case TextZonedSignStyle.AsciiStandard => convertFromAsciiStandard(char)
-        case TextZonedSignStyle.AsciiTranslatedEBCDIC => convertFromAsciiTranslatedEBCDIC(char)
-        case TextZonedSignStyle.AsciiCARealiaModified => convertFromAsciiCARealiaModified(char)
-        case TextZonedSignStyle.AsciiTandemModified => convertFromAsciiTandemModified(char)
-      }
+  def zonedToNumber(num: String, zonedStyle: TextZonedSignStyle, opl: OverpunchLocation.Value): String = {
+    val opindex = opl match {
+      case OverpunchLocation.Start => 0
+      case OverpunchLocation.End => num.length - 1
+      case _ => -1
+    }
 
-      if (opneg && !negative) {
-        negative = true
-        decodedValue.insert(0, '-')
-      }
+    val decodedValue = {
+      if (opl == OverpunchLocation.None) {
+        num
+      } else {
+        val (digit, opneg) = zonedStyle match {
+          case TextZonedSignStyle.AsciiStandard => convertFromAsciiStandard(num(opindex))
+          case TextZonedSignStyle.AsciiTranslatedEBCDIC => convertFromAsciiTranslatedEBCDIC(num(opindex))
+          case TextZonedSignStyle.AsciiCARealiaModified => convertFromAsciiCARealiaModified(num(opindex))
+          case TextZonedSignStyle.AsciiTandemModified => convertFromAsciiTandemModified(num(opindex))
+        }
 
-      decodedValue.append(digit)
-    }
+        val convertedNum = (opneg, opl) match {
+          case (true, OverpunchLocation.Start) => "-" + digit + num.substring(1)
+          case (false, OverpunchLocation.Start) => digit + num.substring(1)
+          case (true, OverpunchLocation.End) => "-" + num.substring(0, opindex) + digit
+          case (false, OverpunchLocation.End) => num.substring(0, opindex) + digit
+          case _ => Assert.impossible()
+        }
 
-    return decodedValue.toString
-  }
+        convertedNum
+      }
+    }
 
-  object OverpunchLocation extends Enumeration {
-    type OverpunchLocation = Value
-    val Start, End, None = Value
+    decodedValue
   }
 
   def zonedFromNumber(num: String, zonedStyle: TextZonedSignStyle, opl: OverpunchLocation.Value): String = {
     val positive = (num.charAt(0) != '-')
-    val inChars = positive match {
-      case true => num.toCharArray
-      case false => num.substring(1).toCharArray
+    val inStr = positive match {
+      case true => num
+      case false => num.substring(1)
     }
     val opindex = opl match {
       case OverpunchLocation.Start => 0
-      case OverpunchLocation.End => inChars.length - 1
+      case OverpunchLocation.End => inStr.length - 1
       case _ => -1
     }
-    val encodedValue = new StringBuilder()
-
-    for (i <- 0 to inChars.length - 1) {
-      val op = (i == opindex)
-      val digit = zonedStyle match {
-        case TextZonedSignStyle.AsciiStandard => convertToAsciiStandard(inChars(i), positive, op)
-        case TextZonedSignStyle.AsciiTranslatedEBCDIC => convertToAsciiTranslatedEBCDIC(inChars(i), positive, op)
-        case TextZonedSignStyle.AsciiCARealiaModified => convertToAsciiCARealiaModified(inChars(i), positive, op)
-        case TextZonedSignStyle.AsciiTandemModified => convertToAsciiTandemModified(inChars(i), positive, op)
-      }
 
-      encodedValue.append(digit)
+    val encodedValue = {
+      if (opl == OverpunchLocation.None) {
+        inStr
+      } else {
+        val digit = zonedStyle match {
+          case TextZonedSignStyle.AsciiStandard => convertToAsciiStandard(inStr(opindex), positive)
+          case TextZonedSignStyle.AsciiTranslatedEBCDIC => convertToAsciiTranslatedEBCDIC(inStr(opindex), positive)
+          case TextZonedSignStyle.AsciiCARealiaModified => convertToAsciiCARealiaModified(inStr(opindex), positive)
+          case TextZonedSignStyle.AsciiTandemModified => convertToAsciiTandemModified(inStr(opindex), positive)
+        }
+
+        val convertedNum = opl match {
+          case OverpunchLocation.Start => digit + inStr.substring(1)
+          case OverpunchLocation.End => inStr.substring(0, opindex) + digit
+          case _ => Assert.impossible()
+        }
+
+        convertedNum
+      }
     }
 
-    return encodedValue.toString
+    encodedValue
   }
 }
diff --git a/daffodil-lib/src/test/scala/org/apache/daffodil/util/TestDecimalUtils.scala b/daffodil-lib/src/test/scala/org/apache/daffodil/util/TestDecimalUtils.scala
index 85a9554..50d6cc2 100644
--- a/daffodil-lib/src/test/scala/org/apache/daffodil/util/TestDecimalUtils.scala
+++ b/daffodil-lib/src/test/scala/org/apache/daffodil/util/TestDecimalUtils.scala
@@ -1252,140 +1252,141 @@ class TestDecimalUtils {
 
   @Test def zonedIntAsciiStandardPos1() {
     val num = "1"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiStandardPos2() {
     val num = "12"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End)
+    System.out.println("Result: " + result)
     assertEquals(result, "12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiStandardPos3() {
     val num = "123"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.None)
     assertEquals(result, "123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.None), num)
   }
 
   @Test def zonedIntAsciiStandardPos4() {
     val num = "1234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiStandardPos5() {
     val num = "000000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "000000000001234567890")
   }
 
   @Test def zonedIntAsciiStandardNeg1() {
     val num = "q"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "-1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiStandardNeg2() {
     val num = "1r"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End)
     assertEquals(result, "-12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiStandardNeg3() {
     val num = "q23"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "-123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiStandardNeg4() {
     val num = "123456789p"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End)
     assertEquals(result, "-1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiStandardNeg5() {
     val num = "p00000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start)
     assertEquals(result, "-000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICPos1() {
     val num = "A"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start)
     assertEquals(result, "1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICPos2() {
     val num = "1B"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End)
     assertEquals(result, "12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICPos3() {
     val num = "123"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None)
     assertEquals(result, "123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICPos4() {
     val num = "A234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start)
     assertEquals(result, "1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICPos5() {
     val num = "00000000000123456789{"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End)
     assertEquals(result, "000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICNeg1() {
     val num = "J"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start)
     assertEquals(result, "-1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICNeg2() {
     val num = "1K"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End)
     assertEquals(result, "-12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICNeg3() {
     val num = "J23"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start)
     assertEquals(result, "-123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICNeg4() {
     val num = "123456789}"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End)
     assertEquals(result, "-1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICNeg5() {
     val num = "}00000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start)
     assertEquals(result, "-000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), num)
   }
@@ -1393,333 +1394,333 @@ class TestDecimalUtils {
 
   @Test def zonedIntAsciiCARealiaModifiedPos1() {
     val num = "1"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start)
     assertEquals(result, "1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedPos2() {
     val num = "12"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End)
     assertEquals(result, "12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedPos3() {
     val num = "123"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.None)
     assertEquals(result, "123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.None), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedPos4() {
     val num = "1234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start)
     assertEquals(result, "1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedPos5() {
     val num = "000000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End)
     assertEquals(result, "000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedNeg1() {
     val num = "!"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start)
     assertEquals(result, "-1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedNeg2() {
     val num = "1\""
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End)
     assertEquals(result, "-12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedNeg3() {
     val num = "!23"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start)
     assertEquals(result, "-123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedNeg4() {
     val num = "123456789 "
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End)
     assertEquals(result, "-1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiCARealiaModifiedNeg5() {
     val num = " 00000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start)
     assertEquals(result, "-000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedPos1() {
     val num = "1"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start)
     assertEquals(result, "1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedPos2() {
     val num = "12"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End)
     assertEquals(result, "12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedPos3() {
     val num = "123"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.None)
     assertEquals(result, "123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.None), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedPos4() {
     val num = "1234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start)
     assertEquals(result, "1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedPos5() {
     val num = "000000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End)
     assertEquals(result, "000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedNeg1() {
     val num = ""
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start)
     assertEquals(result, "-1")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedNeg2() {
     val num = "1‚"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End)
     assertEquals(result, "-12")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedNeg3() {
     val num = "23"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start)
     assertEquals(result, "-123")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedNeg4() {
     val num = "123456789€"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End)
     assertEquals(result, "-1234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), num)
   }
 
   @Test def zonedIntAsciiTandemModifiedNeg5() {
     val num = "€00000000001234567890"
-    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified)
+    val result = zonedToNumber(num, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start)
     assertEquals(result, "-000000000001234567890")
     assertEquals(zonedFromNumber(result, TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), num)
   }
 
   @Test def zonedIntAsciiStandardAllDigits() {
-    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiStandard), "0")
+    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "0")
     assertEquals(zonedFromNumber("0", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "0")
-    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiStandard), "1")
+    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "1")
     assertEquals(zonedFromNumber("1", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "1")
-    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiStandard), "2")
+    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "2")
     assertEquals(zonedFromNumber("2", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "2")
-    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiStandard), "3")
+    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "3")
     assertEquals(zonedFromNumber("3", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "3")
-    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiStandard), "4")
+    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "4")
     assertEquals(zonedFromNumber("4", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "4")
-    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiStandard), "5")
+    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "5")
     assertEquals(zonedFromNumber("5", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "5")
-    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiStandard), "6")
+    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "6")
     assertEquals(zonedFromNumber("6", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "6")
-    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiStandard), "7")
+    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "7")
     assertEquals(zonedFromNumber("7", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "7")
-    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiStandard), "8")
+    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "8")
     assertEquals(zonedFromNumber("8", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "8")
-    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiStandard), "9")
+    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "9")
     assertEquals(zonedFromNumber("9", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "9")
-    assertEquals(zonedToNumber("1p", TextZonedSignStyle.AsciiStandard), "-10")
+    assertEquals(zonedToNumber("1p", TextZonedSignStyle.AsciiStandard, OverpunchLocation.End), "-10")
     assertEquals(zonedFromNumber("-10", TextZonedSignStyle.AsciiStandard, OverpunchLocation.End), "1p")
-    assertEquals(zonedToNumber("q", TextZonedSignStyle.AsciiStandard), "-1")
+    assertEquals(zonedToNumber("q", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-1")
     assertEquals(zonedFromNumber("-1", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "q")
-    assertEquals(zonedToNumber("r", TextZonedSignStyle.AsciiStandard), "-2")
+    assertEquals(zonedToNumber("r", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-2")
     assertEquals(zonedFromNumber("-2", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "r")
-    assertEquals(zonedToNumber("s", TextZonedSignStyle.AsciiStandard), "-3")
+    assertEquals(zonedToNumber("s", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-3")
     assertEquals(zonedFromNumber("-3", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "s")
-    assertEquals(zonedToNumber("t", TextZonedSignStyle.AsciiStandard), "-4")
+    assertEquals(zonedToNumber("t", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-4")
     assertEquals(zonedFromNumber("-4", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "t")
-    assertEquals(zonedToNumber("u", TextZonedSignStyle.AsciiStandard), "-5")
+    assertEquals(zonedToNumber("u", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-5")
     assertEquals(zonedFromNumber("-5", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "u")
-    assertEquals(zonedToNumber("v", TextZonedSignStyle.AsciiStandard), "-6")
+    assertEquals(zonedToNumber("v", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-6")
     assertEquals(zonedFromNumber("-6", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "v")
-    assertEquals(zonedToNumber("w", TextZonedSignStyle.AsciiStandard), "-7")
+    assertEquals(zonedToNumber("w", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-7")
     assertEquals(zonedFromNumber("-7", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "w")
-    assertEquals(zonedToNumber("x", TextZonedSignStyle.AsciiStandard), "-8")
+    assertEquals(zonedToNumber("x", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-8")
     assertEquals(zonedFromNumber("-8", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "x")
-    assertEquals(zonedToNumber("y", TextZonedSignStyle.AsciiStandard), "-9")
+    assertEquals(zonedToNumber("y", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "-9")
     assertEquals(zonedFromNumber("-9", TextZonedSignStyle.AsciiStandard, OverpunchLocation.Start), "y")
   }
 
   @Test def zonedIntAsciiTranslatedEBCDICAllDigits() {
-    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiTranslatedEBCDIC), "0")
+    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "0")
     assertEquals(zonedFromNumber("0", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "0")
-    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiTranslatedEBCDIC), "1")
+    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "1")
     assertEquals(zonedFromNumber("1", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "1")
-    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiTranslatedEBCDIC), "2")
+    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "2")
     assertEquals(zonedFromNumber("2", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "2")
-    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiTranslatedEBCDIC), "3")
+    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "3")
     assertEquals(zonedFromNumber("3", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "3")
-    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiTranslatedEBCDIC), "4")
+    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "4")
     assertEquals(zonedFromNumber("4", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "4")
-    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiTranslatedEBCDIC), "5")
+    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "5")
     assertEquals(zonedFromNumber("5", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "5")
-    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiTranslatedEBCDIC), "6")
+    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "6")
     assertEquals(zonedFromNumber("6", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "6")
-    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiTranslatedEBCDIC), "7")
+    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "7")
     assertEquals(zonedFromNumber("7", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "7")
-    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiTranslatedEBCDIC), "8")
+    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "8")
     assertEquals(zonedFromNumber("8", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "8")
-    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiTranslatedEBCDIC), "9")
+    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "9")
     assertEquals(zonedFromNumber("9", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.None), "9")
-    assertEquals(zonedToNumber("{", TextZonedSignStyle.AsciiTranslatedEBCDIC), "0")
+    assertEquals(zonedToNumber("{", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "0")
     assertEquals(zonedFromNumber("0", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "{")
-    assertEquals(zonedToNumber("A", TextZonedSignStyle.AsciiTranslatedEBCDIC), "1")
+    assertEquals(zonedToNumber("A", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "1")
     assertEquals(zonedFromNumber("1", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "A")
-    assertEquals(zonedToNumber("B", TextZonedSignStyle.AsciiTranslatedEBCDIC), "2")
+    assertEquals(zonedToNumber("B", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "2")
     assertEquals(zonedFromNumber("2", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "B")
-    assertEquals(zonedToNumber("C", TextZonedSignStyle.AsciiTranslatedEBCDIC), "3")
+    assertEquals(zonedToNumber("C", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "3")
     assertEquals(zonedFromNumber("3", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "C")
-    assertEquals(zonedToNumber("D", TextZonedSignStyle.AsciiTranslatedEBCDIC), "4")
+    assertEquals(zonedToNumber("D", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "4")
     assertEquals(zonedFromNumber("4", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "D")
-    assertEquals(zonedToNumber("E", TextZonedSignStyle.AsciiTranslatedEBCDIC), "5")
+    assertEquals(zonedToNumber("E", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "5")
     assertEquals(zonedFromNumber("5", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "E")
-    assertEquals(zonedToNumber("F", TextZonedSignStyle.AsciiTranslatedEBCDIC), "6")
+    assertEquals(zonedToNumber("F", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "6")
     assertEquals(zonedFromNumber("6", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "F")
-    assertEquals(zonedToNumber("G", TextZonedSignStyle.AsciiTranslatedEBCDIC), "7")
+    assertEquals(zonedToNumber("G", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "7")
     assertEquals(zonedFromNumber("7", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "G")
-    assertEquals(zonedToNumber("H", TextZonedSignStyle.AsciiTranslatedEBCDIC), "8")
+    assertEquals(zonedToNumber("H", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "8")
     assertEquals(zonedFromNumber("8", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "H")
-    assertEquals(zonedToNumber("I", TextZonedSignStyle.AsciiTranslatedEBCDIC), "9")
+    assertEquals(zonedToNumber("I", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "9")
     assertEquals(zonedFromNumber("9", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "I")
-    assertEquals(zonedToNumber("1}", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-10")
+    assertEquals(zonedToNumber("1}", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), "-10")
     assertEquals(zonedFromNumber("-10", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.End), "1}")
-    assertEquals(zonedToNumber("J", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-1")
+    assertEquals(zonedToNumber("J", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-1")
     assertEquals(zonedFromNumber("-1", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "J")
-    assertEquals(zonedToNumber("K", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-2")
+    assertEquals(zonedToNumber("K", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-2")
     assertEquals(zonedFromNumber("-2", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "K")
-    assertEquals(zonedToNumber("L", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-3")
+    assertEquals(zonedToNumber("L", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-3")
     assertEquals(zonedFromNumber("-3", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "L")
-    assertEquals(zonedToNumber("M", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-4")
+    assertEquals(zonedToNumber("M", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-4")
     assertEquals(zonedFromNumber("-4", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "M")
-    assertEquals(zonedToNumber("N", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-5")
+    assertEquals(zonedToNumber("N", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-5")
     assertEquals(zonedFromNumber("-5", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "N")
-    assertEquals(zonedToNumber("O", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-6")
+    assertEquals(zonedToNumber("O", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-6")
     assertEquals(zonedFromNumber("-6", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "O")
-    assertEquals(zonedToNumber("P", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-7")
+    assertEquals(zonedToNumber("P", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-7")
     assertEquals(zonedFromNumber("-7", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "P")
-    assertEquals(zonedToNumber("Q", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-8")
+    assertEquals(zonedToNumber("Q", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-8")
     assertEquals(zonedFromNumber("-8", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "Q")
-    assertEquals(zonedToNumber("R", TextZonedSignStyle.AsciiTranslatedEBCDIC), "-9")
+    assertEquals(zonedToNumber("R", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "-9")
     assertEquals(zonedFromNumber("-9", TextZonedSignStyle.AsciiTranslatedEBCDIC, OverpunchLocation.Start), "R")
   }
 
   @Test def zonedIntAsciiCARealiaModifiedAllDigits() {
-    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiCARealiaModified), "0")
+    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "0")
     assertEquals(zonedFromNumber("0", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "0")
-    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiCARealiaModified), "1")
+    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "1")
     assertEquals(zonedFromNumber("1", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "1")
-    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiCARealiaModified), "2")
+    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "2")
     assertEquals(zonedFromNumber("2", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "2")
-    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiCARealiaModified), "3")
+    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "3")
     assertEquals(zonedFromNumber("3", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "3")
-    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiCARealiaModified), "4")
+    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "4")
     assertEquals(zonedFromNumber("4", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "4")
-    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiCARealiaModified), "5")
+    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "5")
     assertEquals(zonedFromNumber("5", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "5")
-    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiCARealiaModified), "6")
+    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "6")
     assertEquals(zonedFromNumber("6", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "6")
-    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiCARealiaModified), "7")
+    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "7")
     assertEquals(zonedFromNumber("7", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "7")
-    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiCARealiaModified), "8")
+    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "8")
     assertEquals(zonedFromNumber("8", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "8")
-    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiCARealiaModified), "9")
+    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "9")
     assertEquals(zonedFromNumber("9", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "9")
-    assertEquals(zonedToNumber("1 ", TextZonedSignStyle.AsciiCARealiaModified), "-10")
+    assertEquals(zonedToNumber("1 ", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), "-10")
     assertEquals(zonedFromNumber("-10", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.End), "1 ")
-    assertEquals(zonedToNumber("!", TextZonedSignStyle.AsciiCARealiaModified), "-1")
+    assertEquals(zonedToNumber("!", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-1")
     assertEquals(zonedFromNumber("-1", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "!")
-    assertEquals(zonedToNumber("\"", TextZonedSignStyle.AsciiCARealiaModified), "-2")
+    assertEquals(zonedToNumber("\"", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-2")
     assertEquals(zonedFromNumber("-2", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "\"")
-    assertEquals(zonedToNumber("#", TextZonedSignStyle.AsciiCARealiaModified), "-3")
+    assertEquals(zonedToNumber("#", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-3")
     assertEquals(zonedFromNumber("-3", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "#")
-    assertEquals(zonedToNumber("$", TextZonedSignStyle.AsciiCARealiaModified), "-4")
+    assertEquals(zonedToNumber("$", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-4")
     assertEquals(zonedFromNumber("-4", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "$")
-    assertEquals(zonedToNumber("%", TextZonedSignStyle.AsciiCARealiaModified), "-5")
+    assertEquals(zonedToNumber("%", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-5")
     assertEquals(zonedFromNumber("-5", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "%")
-    assertEquals(zonedToNumber("&", TextZonedSignStyle.AsciiCARealiaModified), "-6")
+    assertEquals(zonedToNumber("&", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-6")
     assertEquals(zonedFromNumber("-6", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "&")
-    assertEquals(zonedToNumber("'", TextZonedSignStyle.AsciiCARealiaModified), "-7")
+    assertEquals(zonedToNumber("'", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-7")
     assertEquals(zonedFromNumber("-7", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "'")
-    assertEquals(zonedToNumber("(", TextZonedSignStyle.AsciiCARealiaModified), "-8")
+    assertEquals(zonedToNumber("(", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-8")
     assertEquals(zonedFromNumber("-8", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "(")
-    assertEquals(zonedToNumber(")", TextZonedSignStyle.AsciiCARealiaModified), "-9")
+    assertEquals(zonedToNumber(")", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), "-9")
     assertEquals(zonedFromNumber("-9", TextZonedSignStyle.AsciiCARealiaModified, OverpunchLocation.Start), ")")
   }
 
   @Test def zonedIntAsciiTandemModifiedAllDigits() {
-    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiTandemModified), "0")
+    assertEquals(zonedToNumber("0", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "0")
     assertEquals(zonedFromNumber("0", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "0")
-    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiTandemModified), "1")
+    assertEquals(zonedToNumber("1", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "1")
     assertEquals(zonedFromNumber("1", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "1")
-    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiTandemModified), "2")
+    assertEquals(zonedToNumber("2", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "2")
     assertEquals(zonedFromNumber("2", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "2")
-    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiTandemModified), "3")
+    assertEquals(zonedToNumber("3", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "3")
     assertEquals(zonedFromNumber("3", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "3")
-    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiTandemModified), "4")
+    assertEquals(zonedToNumber("4", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "4")
     assertEquals(zonedFromNumber("4", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "4")
-    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiTandemModified), "5")
+    assertEquals(zonedToNumber("5", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "5")
     assertEquals(zonedFromNumber("5", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "5")
-    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiTandemModified), "6")
+    assertEquals(zonedToNumber("6", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "6")
     assertEquals(zonedFromNumber("6", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "6")
-    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiTandemModified), "7")
+    assertEquals(zonedToNumber("7", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "7")
     assertEquals(zonedFromNumber("7", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "7")
-    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiTandemModified), "8")
+    assertEquals(zonedToNumber("8", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "8")
     assertEquals(zonedFromNumber("8", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "8")
-    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiTandemModified), "9")
+    assertEquals(zonedToNumber("9", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "9")
     assertEquals(zonedFromNumber("9", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "9")
-    assertEquals(zonedToNumber("1€", TextZonedSignStyle.AsciiTandemModified), "-10")
+    assertEquals(zonedToNumber("1€", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), "-10")
     assertEquals(zonedFromNumber("-10", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.End), "1€")
-    assertEquals(zonedToNumber("", TextZonedSignStyle.AsciiTandemModified), "-1")
+    assertEquals(zonedToNumber("", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-1")
     assertEquals(zonedFromNumber("-1", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "")
-    assertEquals(zonedToNumber("‚", TextZonedSignStyle.AsciiTandemModified), "-2")
+    assertEquals(zonedToNumber("‚", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-2")
     assertEquals(zonedFromNumber("-2", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "‚")
-    assertEquals(zonedToNumber("ƒ", TextZonedSignStyle.AsciiTandemModified), "-3")
+    assertEquals(zonedToNumber("ƒ", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-3")
     assertEquals(zonedFromNumber("-3", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "ƒ")
-    assertEquals(zonedToNumber("„", TextZonedSignStyle.AsciiTandemModified), "-4")
+    assertEquals(zonedToNumber("„", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-4")
     assertEquals(zonedFromNumber("-4", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "„")
-    assertEquals(zonedToNumber("…", TextZonedSignStyle.AsciiTandemModified), "-5")
+    assertEquals(zonedToNumber("…", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-5")
     assertEquals(zonedFromNumber("-5", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "…")
-    assertEquals(zonedToNumber("†", TextZonedSignStyle.AsciiTandemModified), "-6")
+    assertEquals(zonedToNumber("†", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-6")
     assertEquals(zonedFromNumber("-6", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "†")
-    assertEquals(zonedToNumber("‡", TextZonedSignStyle.AsciiTandemModified), "-7")
+    assertEquals(zonedToNumber("‡", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-7")
     assertEquals(zonedFromNumber("-7", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "‡")
-    assertEquals(zonedToNumber("ˆ", TextZonedSignStyle.AsciiTandemModified), "-8")
+    assertEquals(zonedToNumber("ˆ", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-8")
     assertEquals(zonedFromNumber("-8", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "ˆ")
-    assertEquals(zonedToNumber("‰", TextZonedSignStyle.AsciiTandemModified), "-9")
+    assertEquals(zonedToNumber("‰", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "-9")
     assertEquals(zonedFromNumber("-9", TextZonedSignStyle.AsciiTandemModified, OverpunchLocation.Start), "‰")
   }
 }
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ConvertZonedNumberUnparser.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ConvertZonedNumberUnparser.scala
index efcfa01..eef0cce 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ConvertZonedNumberUnparser.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ConvertZonedNumberUnparser.scala
@@ -21,7 +21,7 @@ import org.apache.daffodil.schema.annotation.props.gen.TextZonedSignStyle
 import org.apache.daffodil.processors._
 import org.apache.daffodil.util.DecimalUtils
 import org.apache.daffodil.util.DecimalUtils.OverpunchLocation
-import org.apache.daffodil.processors.parsers.ConvertZonedNumberParserUnparserHelperBase
+import org.apache.daffodil.processors.parsers.ConvertTextNumberParserUnparserHelperBase
 
 case class ConvertZonedCombinatorUnparser(
   rd: TermRuntimeData,
@@ -36,14 +36,14 @@ case class ConvertZonedCombinatorUnparser(
   override def unparse(state: UState): Unit = {
     converterUnparser.unparse1(state)
 
-    if (state.processorStatus ne Success) return
-
-    valueUnparser.unparse1(state)
+    if (state.processorStatus eq Success) {
+      valueUnparser.unparse1(state)
+    }
   }
 }
 
 case class ConvertZonedNumberUnparser[S](
-  helper: ConvertZonedNumberParserUnparserHelperBase[S],
+  helper: ConvertTextNumberParserUnparserHelperBase[S],
   pattern: String,
   zonedSignStyle: TextZonedSignStyle,
   override val context: ElementRuntimeData)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PrimitivesTextNumber1.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PrimitivesTextNumber1.scala
index d9d6614..a2b933d 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PrimitivesTextNumber1.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PrimitivesTextNumber1.scala
@@ -442,7 +442,7 @@ abstract class NumberFormatFactoryBase[S](parserHelper: ConvertTextNumberParserU
 
   protected def generateNumFormat(decimalSepList: Maybe[List[Character]],
     groupingSep: Maybe[Character],
-    exponentRep: String,
+    exponentRep: Maybe[String],
     infRep: Maybe[String],
     nanRep: Maybe[String],
     checkPolicy: TextNumberCheckPolicy,
@@ -463,7 +463,9 @@ abstract class NumberFormatFactoryBase[S](parserHelper: ConvertTextNumberParserU
     }
 
     // TODO: this is allowed to be case insenstive, ICU doesn't support that
-    dfs.setExponentSeparator(exponentRep)
+    if (exponentRep.isDefined) {
+      dfs.setExponentSeparator(exponentRep.get)
+    }
 
     if (infRep.isDefined) {
       // TODO: this is allowed to be case insensitive, ICU doesn't support that
@@ -557,7 +559,7 @@ class NumberFormatFactoryStatic[S](context: ThrowsSDE,
   parserHelper: ConvertTextNumberParserUnparserHelperBase[S],
   decimalSepExpEv: Maybe[Evaluatable[List[String]]],
   groupingSepExpEv: Maybe[Evaluatable[String]],
-  exponentRepExpEv: Evaluatable[String],
+  exponentRepExpEv: Maybe[Evaluatable[String]],
   infRep: Maybe[String],
   nanRep: Maybe[String],
   checkPolicy: TextNumberCheckPolicy,
@@ -566,9 +568,6 @@ class NumberFormatFactoryStatic[S](context: ThrowsSDE,
   roundingMode: Maybe[TextNumberRoundingMode],
   roundingIncrement: MaybeDouble)
   extends NumberFormatFactoryBase[S](parserHelper) {
-  Assert.invariant((!decimalSepExpEv.isDefined || decimalSepExpEv.get.isConstant) &&
-    (!groupingSepExpEv.isDefined || groupingSepExpEv.get.isConstant) &&
-    exponentRepExpEv.isConstant)
 
   val decSep =
     if (decimalSepExpEv.isEmpty) Nope else One {
@@ -582,17 +581,18 @@ class NumberFormatFactoryStatic[S](context: ThrowsSDE,
       getGroupingSep(gse, context)
     }
 
-  val expRep = {
-    Assert.invariant(exponentRepExpEv.isConstant)
-    getExponentRep(exponentRepExpEv.maybeConstant.get, context)
-  }
+  val expRep =
+    if (exponentRepExpEv.isEmpty) Nope else One {
+      Assert.invariant(exponentRepExpEv.get.isConstant)
+      getExponentRep(exponentRepExpEv.get.maybeConstant.get, context)
+    }
 
   val roundingInc: MaybeDouble = if (roundingIncrement.isEmpty) MaybeDouble.Nope else MaybeDouble { getRoundingIncrement(roundingIncrement.value, context) }
 
   checkUnique(
     decSep,
     groupSep,
-    One(expRep),
+    expRep,
     infRep,
     nanRep,
     parserHelper.zeroRepListRaw,
@@ -623,7 +623,7 @@ class NumberFormatFactoryDynamic[S](staticContext: ThrowsSDE,
   parserHelper: ConvertTextNumberParserUnparserHelperBase[S],
   decimalSepExpEv: Maybe[Evaluatable[List[String]]],
   groupingSepExpEv: Maybe[Evaluatable[String]],
-  exponentRepExpEv: Evaluatable[String],
+  exponentRepExpEv: Maybe[Evaluatable[String]],
   infRep: Maybe[String],
   nanRep: Maybe[String],
   checkPolicy: TextNumberCheckPolicy,
@@ -644,14 +644,14 @@ class NumberFormatFactoryDynamic[S](staticContext: ThrowsSDE,
       (a: String) => getGroupingSep(a, staticContext)
     }
 
-  val exponentRepCached: CachedDynamic[String, String] =
-    cacheConstantExpression(exponentRepExpEv) {
+  val exponentRepCached: Maybe[CachedDynamic[String, String]] =
+    cacheConstantExpressionMaybe(exponentRepExpEv) {
       (a: String) => getExponentRep(a, staticContext)
     }
 
   checkUnique(getStaticMaybe(decimalSepListCached),
     getStaticMaybe(groupingSepCached),
-    getStatic(exponentRepCached),
+    getStaticMaybe(exponentRepCached),
     infRep,
     nanRep,
     parserHelper.zeroRepListRaw,
@@ -675,7 +675,7 @@ class NumberFormatFactoryDynamic[S](staticContext: ThrowsSDE,
         }
     }
 
-    val exponentRep = evalWithConversion(state, exponentRepCached) {
+    val exponentRep = evalWithConversionMaybe(state, exponentRepCached) {
       (s: ParseOrUnparseState, c: String) =>
         {
           getExponentRep(c, s)
@@ -685,7 +685,7 @@ class NumberFormatFactoryDynamic[S](staticContext: ThrowsSDE,
     checkUnique(
       decimalSepList,
       groupingSep,
-      One(exponentRep),
+      exponentRep,
       infRep,
       nanRep,
       parserHelper.zeroRepListRaw,
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ZonedTextParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ZonedTextParsers.scala
index bf273d9..0b48093 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ZonedTextParsers.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ZonedTextParsers.scala
@@ -17,25 +17,16 @@
 
 package org.apache.daffodil.processors.parsers
 
-import org.apache.daffodil.schema.annotation.props.gen. { TextNumberCheckPolicy, TextNumberRounding, TextNumberRoundingMode, TextZonedSignStyle }
-import org.apache.daffodil.exceptions.ThrowsSDE
+import org.apache.daffodil.schema.annotation.props.gen.TextZonedSignStyle
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.exceptions.UnsuppressableException
-import org.apache.daffodil.util.Maybe
 import org.apache.daffodil.util.DecimalUtils
+import org.apache.daffodil.util.DecimalUtils.OverpunchLocation
 import java.text.ParsePosition
-import com.ibm.icu.text.DecimalFormat
-import org.apache.daffodil.util.MaybeDouble
-import org.apache.daffodil.util.MaybeDouble
 import java.lang.{ Number => JNumber }
-import java.math.{ BigDecimal => JBigDecimal, BigInteger => JBigInt }
 import org.apache.daffodil.infoset.DISimple
 import org.apache.daffodil.processors.ElementRuntimeData
-import org.apache.daffodil.processors.ParseOrUnparseState
 import org.apache.daffodil.processors.Success
-import java.lang.{ Number => JNumber }
-import java.math.{ BigDecimal => JBigDecimal }
-import java.math.{ BigInteger => JBigInt }
 import org.apache.daffodil.processors.TermRuntimeData
 
 case class ConvertZonedCombinatorParser(
@@ -50,16 +41,16 @@ case class ConvertZonedCombinatorParser(
 
   def parse(start: PState): Unit = {
     valueParser.parse1(start)
-    if (start.processorStatus ne Success) {
-      return
+    if (start.processorStatus eq Success) {
+      converterParser.parse1(start)
     }
-    converterParser.parse1(start)
   }
 }
 
 case class ConvertZonedNumberParser[S](
-  helper: ConvertZonedNumberParserUnparserHelperBase[S],
-  nff: ZonedFormatFactoryBase[S],
+  helper: ConvertTextNumberParserUnparserHelperBase[S],
+  pattern: String,
+  nff: NumberFormatFactoryBase[S],
   zonedSignStyle: TextZonedSignStyle,
   override val context: ElementRuntimeData) extends TextPrimParser {
   override lazy val runtimeDependencies = Nil
@@ -76,12 +67,22 @@ case class ConvertZonedNumberParser[S](
       return
     }
 
+    val opindex = pattern.indexOf('+')
+    val opl = {
+      if (opindex == 0)
+        OverpunchLocation.Start
+      else if (opindex == pattern.length - 1)
+        OverpunchLocation.End
+      else
+        OverpunchLocation.None
+    }
+
     var checkLength = str.length
     val numValue = {
       val df = nff.getNumFormat(start)
       val pos = new ParsePosition(0)
       val num = try {
-        val decodedNum = DecimalUtils.zonedToNumber(str, zonedSignStyle)
+        val decodedNum = DecimalUtils.zonedToNumber(str, zonedSignStyle, opl)
         if (decodedNum(0) == '-')
           checkLength = checkLength + 1
         df.get.parse(decodedNum, pos)
@@ -119,319 +120,7 @@ case class ConvertZonedNumberParser[S](
       numValue
     }
 
-    Assert.invariant(!numValue.isInstanceOf[String])
     node.overwriteDataValue(numValue.asInstanceOf[JNumber])
 
   }
 }
-
-abstract class ConvertZonedNumberParserUnparserHelperBase[S]() extends Serializable {
-  val xsdType: String
-  val prettyType: String
-
-  def getNum(s: Number): S
-  def isInt: Boolean
-  def isInvalidRange(n: java.lang.Number): Boolean
-  def getStringFormat(n: S): String
-}
-
-abstract class ConvertZonedIntegerNumberParserUnparserHelper[S]()
-  extends ConvertZonedNumberParserUnparserHelperBase[S]() {
-  override def isInt = true
-
-  override def getStringFormat(n: S): String = n.toString()
-
-  def isInvalidRange(n: java.lang.Number): Boolean = {
-    //
-    // Note: Scala has no class analogous to java.lang.Number. There's no common
-    // base class above its number types (as there isn't above the Java *primitive* number types.)
-    //
-    // We're being handed here a java 'boxed' number type, and those have common parent Number.
-    //
-    // println("number's actual type is: " + n.getClass.getName)
-    //
-    // This method only for things that fit in range of a Long. (i.e., not unbounded size Integer, and not unsignedLong
-    // Nevertheless, if invalid data much too long for the real numeric type is what is found in the data
-    // then a java BigInteger (or maybe even BigDecimal might get passed here.
-    //
-    // The only thing we can check is whether there is conversion to a long available.
-    // e.g., like this: Assert.invariant(n.isInstanceOf[{ def longValue : Long}])
-    // But that's eliminated by erasure, so we'll just do without.
-    //
-    val l = n.longValue
-
-    // check for overflow/underflow.
-    val orig = new JBigDecimal(n.toString)
-    val newl = new JBigDecimal(l)
-    if (orig.compareTo(newl) != 0) {
-      true
-    } else {
-      l < min || l > max
-    }
-  }
-  def min: Long
-  def max: Long
-}
-
-abstract class ConvertZonedFloatingPointNumberParserUnparserHelper[S]()
-  extends ConvertZonedNumberParserUnparserHelperBase[S]() {
-  override def isInt = false
-  override def getStringFormat(n: S): String = {
-
-    //val trailingZeroes = """0*(?!<[1-9])$"""
-    val trailingZeroes = """(?<=[1-9])(0*)$""".r
-    val trailingZeroesBeforeExponent = """(?<=[1-9])(0*?)(?=E.*)""".r
-
-    val nAsStr = n.toString()
-
-    if (nAsStr.contains("E") || nAsStr.contains("e")) {
-      // Exponent
-      trailingZeroesBeforeExponent.replaceAllIn(nAsStr, "")
-    } else {
-      trailingZeroes.replaceAllIn(nAsStr, "")
-    }
-
-    nAsStr
-  }
-
-}
-
-case class ConvertZonedIntegerParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[JBigInt]() {
-
-  override def getNum(num: Number) = new JBigInt(num.toString)
-  override val xsdType = "integer"
-  override val prettyType = "Unlimited Size Integer"
-  override def isInvalidRange(n: java.lang.Number): Boolean = false
-  def min = -1 // ignored
-  def max = -1 // ignored
-}
-
-case class ConvertZonedNonNegativeIntegerParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[JBigInt]() {
-
-  override def getNum(num: Number) = new JBigInt(num.toString)
-  override val xsdType = "nonNegativeInteger"
-  override val prettyType = "Unlimited Size Non Negative Integer"
-  override def isInvalidRange(n: java.lang.Number): Boolean = {
-    val value = new JBigDecimal(n.toString())
-    val isNegative = value.signum == -1
-    if (isNegative) return true
-    false
-  }
-  def min = -1 // ignored
-  def max = -1 // ignored
-}
-
-case class ConvertZonedLongParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Long]() {
-
-  override def getNum(num: Number) = num.longValue
-  override val xsdType = "long"
-  override val prettyType = "Long Integer"
-  val min = Long.MinValue
-  val max = Long.MaxValue
-}
-
-case class ConvertZonedIntParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Int]() {
-
-  override def getNum(num: Number) = num.intValue
-  override val xsdType = "int"
-  override val prettyType = "Integer"
-  val min = Int.MinValue.toLong
-  val max = Int.MaxValue.toLong
-}
-
-case class ConvertZonedShortParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Short]() {
-
-  override def getNum(num: Number) = num.shortValue
-  override val xsdType = "short"
-  override val prettyType = "Short Integer"
-  val min = Short.MinValue.toLong
-  val max = Short.MaxValue.toLong
-}
-
-case class ConvertZonedByteParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Byte]() {
-
-  override def getNum(num: Number) = num.byteValue
-  override val xsdType = "byte"
-  override val prettyType = "Byte"
-  val min = Byte.MinValue.toLong
-  val max = Byte.MaxValue.toLong
-}
-
-case class ConvertZonedUnsignedLongParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[JBigInt]() {
-
-  override def getNum(num: Number) = new JBigInt(num.toString)
-  override val xsdType = "unsignedLong"
-  override val prettyType = "Unsigned Long"
-  override def isInvalidRange(jn: java.lang.Number) = {
-    jn match {
-      case n: JBigInt => {
-        n.compareTo(JBigInt.ZERO) < 0 || n.compareTo(JBigInt.ONE.shiftLeft(64)) >= 0
-      }
-      case _ => {
-        val n = jn.longValue()
-        n < 0 // note: the other side of the check is inherently ok since a Long must be smaller than an unsignedLong.
-      }
-    }
-  }
-  val min = 0.toLong
-  val max = -1.toLong // unused.
-}
-
-case class ConvertZonedUnsignedIntParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Long]() {
-
-  override def getNum(num: Number) = num.longValue
-  override val xsdType = "unsignedInt"
-  override val prettyType = "Unsigned Integer"
-  val min = 0L
-  val max = (1L << 32) - 1L
-}
-
-case class ConvertZonedUnsignedShortParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Int]() {
-
-  override def getNum(num: Number) = num.intValue
-  override val xsdType = "unsignedShort"
-  override val prettyType = "Unsigned Short"
-  val min = 0L
-  val max = (1L << 16) - 1L
-}
-
-case class ConvertZonedUnsignedByteParserUnparserHelper[S]()
-  extends ConvertZonedIntegerNumberParserUnparserHelper[Short]() {
-
-  override def getNum(num: Number) = num.shortValue
-  override val xsdType = "unsignedByte"
-  override val prettyType = "Unsigned Byte"
-  val min = 0L
-  val max = (1L << 8) - 1L
-}
-
-case class ConvertZonedDecimalParserUnparserHelper[S]()
-  extends ConvertZonedFloatingPointNumberParserUnparserHelper[JBigDecimal]() {
-
-  override def getNum(num: Number) = new JBigDecimal(num.toString)
-  override val xsdType = "decimal"
-  override val prettyType = "Unlimited Size Decimal"
-  override def isInvalidRange(n: java.lang.Number): Boolean = false
-
-  override def getStringFormat(n: JBigDecimal): String = {
-    n.toPlainString()
-  }
-}
-
-abstract class ZonedFormatFactoryBase[S](parserHelper: ConvertZonedNumberParserUnparserHelperBase[S]) extends Serializable {
-
-  protected def checkUnique(
-    context: ThrowsSDE) = {
-
-    import scala.collection.mutable.{ HashMap, MultiMap, Set }
-
-    val mm = new HashMap[String, Set[String]] with MultiMap[String, String]
-
-    val dupes = mm.filter { case (k, s) => s.size > 1 }
-    val dupeStrings = dupes.map {
-      case (k, s) =>
-        "Non-distinct property '%s' found in: %s".format(k, s.mkString(", "))
-    }
-    context.schemaDefinitionUnless(dupeStrings.size == 0, dupeStrings.mkString("\n"))
-  }
-
-  protected def generateNumFormat(
-    checkPolicy: TextNumberCheckPolicy,
-    pattern: String,
-    rounding: TextNumberRounding,
-    roundingMode: Maybe[TextNumberRoundingMode],
-    roundingIncrement: MaybeDouble) = {
-
-    /* Need to remove the '+' from the number pattern as '+' is only
-     * used to indicate which digit of the number is overpunched when
-     * dealing with zoned decimal formats. If the '+' is not removed
-     * DecimalFormat will attempt to use it as an indicator for exponent
-     * numbers, which will most likely not match the zoned number being
-     * parsed */
-    val df = new DecimalFormat(pattern.replace("+", ""))
-
-    val cp = checkPolicy match {
-      case TextNumberCheckPolicy.Strict => true
-      case TextNumberCheckPolicy.Lax => false
-    }
-    df.setParseStrict(cp)
-
-    rounding match {
-      case TextNumberRounding.Pattern => {
-        df.setRoundingMode(JBigDecimal.ROUND_HALF_EVEN)
-      }
-      case TextNumberRounding.Explicit => {
-        val rm = roundingMode.get match {
-          case TextNumberRoundingMode.RoundCeiling => JBigDecimal.ROUND_CEILING
-          case TextNumberRoundingMode.RoundFloor => JBigDecimal.ROUND_FLOOR
-          case TextNumberRoundingMode.RoundDown => JBigDecimal.ROUND_DOWN
-          case TextNumberRoundingMode.RoundUp => JBigDecimal.ROUND_UP
-          case TextNumberRoundingMode.RoundHalfEven => JBigDecimal.ROUND_HALF_EVEN
-          case TextNumberRoundingMode.RoundHalfDown => JBigDecimal.ROUND_HALF_DOWN
-          case TextNumberRoundingMode.RoundHalfUp => JBigDecimal.ROUND_HALF_UP
-          case TextNumberRoundingMode.RoundUnnecessary => JBigDecimal.ROUND_UNNECESSARY
-        }
-        df.setRoundingMode(rm)
-        df.setRoundingIncrement(roundingIncrement.get)
-      }
-    }
-
-    if (parserHelper.isInt) {
-      df.setMaximumFractionDigits(0)
-      df.setDecimalSeparatorAlwaysShown(false)
-      df.setParseIntegerOnly(true)
-    }
-
-    df
-  }
-
-  protected def getRoundingIncrement(roundingInc: Double, context: ThrowsSDE): Double = {
-    context.schemaDefinitionUnless(roundingInc >= 0, "textNumberRoundingIncrement cannot be negative")
-    roundingInc
-  }
-
-  // as per ICU4J documentation, "DecimalFormat objects are not
-  // synchronized. Multiple threads should not access one formatter
-  // concurrently."
-  def getNumFormat(state: ParseOrUnparseState): ThreadLocal[DecimalFormat]
-
-}
-
-class ZonedFormatFactoryStatic[S](context: ThrowsSDE,
-  parserHelper: ConvertZonedNumberParserUnparserHelperBase[S],
-  checkPolicy: TextNumberCheckPolicy,
-  pattern: String,
-  rounding: TextNumberRounding,
-  roundingMode: Maybe[TextNumberRoundingMode],
-  roundingIncrement: MaybeDouble)
-  extends ZonedFormatFactoryBase[S](parserHelper) {
-
-  val roundingInc: MaybeDouble = if (roundingIncrement.isEmpty) MaybeDouble.Nope else MaybeDouble { getRoundingIncrement(roundingIncrement.value, context) }
-
-  checkUnique(
-    context)
-
-  @transient lazy val numFormat = new ThreadLocal[DecimalFormat] {
-    override def initialValue() = {
-      generateNumFormat(
-        checkPolicy,
-        pattern,
-        rounding,
-        roundingMode,
-        roundingInc)
-    }
-  }
-
-  def getNumFormat(state: ParseOrUnparseState): ThreadLocal[DecimalFormat] = {
-    numFormat
-  }
-}
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section13/zoned/zoned.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section13/zoned/zoned.tdml
index 09dd4d4..3e1cd8f 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section13/zoned/zoned.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section13/zoned/zoned.tdml
@@ -31,8 +31,10 @@
 
     <xs:element name="int01" type="xs:int" dfdl:length="4" dfdl:textNumberPattern="+00@00" />
     <xs:element name="int02" type="xs:int" dfdl:length="4" dfdl:textNumberPattern="0000" />
-    <xs:element name="uint03" type="xs:unsignedInt" dfdl:length="4" dfdl:textNumberPattern="0000" dfdl:textNumberCheckPolicy="lax"/>
+    <xs:element name="int03" type="xs:int" dfdl:length="4" dfdl:textNumberPattern="+00E00" />
+    <xs:element name="uint01" type="xs:unsignedInt" dfdl:length="4" dfdl:textNumberPattern="0000" dfdl:textNumberCheckPolicy="lax"/>
     <xs:element name="int04" type="xs:int" dfdl:length="4" dfdl:textNumberPattern="+00;00" />
+    <xs:element name="int05" type="xs:int" dfdl:length="4" dfdl:textNumberPattern="+0000+" />
     <xs:element name="float01" type="xs:float" dfdl:length="4" dfdl:textNumberPattern="+00;00" />
     <xs:element name="double01" type="xs:double" dfdl:length="4" dfdl:textNumberPattern="+00;00" />
 
@@ -78,7 +80,7 @@
 
   </tdml:parserTestCase>
 
-  <tdml:parserTestCase name="zoned_textNumberPattern_fail03" root="uint03" model="s1"
+  <tdml:parserTestCase name="zoned_textNumberPattern_fail03" root="uint01" model="s1"
     description="This test should fail because '+' must be the first or last character in the textNumberPattern when using zoned numbers and textNumberCheckPolicy=strict">
 
     <tdml:document>
@@ -103,6 +105,30 @@
 
   </tdml:parserTestCase>
 
+  <tdml:parserTestCase name="zoned_textNumberPattern_fail05" root="int03" model="s1"
+    description="This test should fail because 'E' is not an allowed character in the textNumberPattern for zoned numbers">
+
+    <tdml:document>
+      <tdml:documentPart type="text">1988</tdml:documentPart>
+    </tdml:document>
+    <tdml:errors>
+      <tdml:error>Invalid characters used in textNubmerPattern for zoned number</tdml:error>
+    </tdml:errors>
+
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="zoned_textNumberPattern_fail06" root="int05" model="s1"
+    description="This test should fail because '+' is not allowed to be at both the start and end of the textNumberPattern">
+
+    <tdml:document>
+      <tdml:documentPart type="text">1988</tdml:documentPart>
+    </tdml:document>
+    <tdml:errors>
+      <tdml:error>The textNumberPattern may either begin or end with a '+', not both</tdml:error>
+    </tdml:errors>
+
+  </tdml:parserTestCase>
+
   <tdml:parserTestCase name="zoned_float_fail01" root="float01" model="s1"
     description="This test should fail because floats are not supported with zoned decimal">
 
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section13/zoned/TestZoned.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section13/zoned/TestZoned.scala
index 1fd36f8..00bf084 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/section13/zoned/TestZoned.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section13/zoned/TestZoned.scala
@@ -38,6 +38,8 @@ class TestZoned {
   @Test def testZonedPatternFail02(): Unit = { runner.runOneTest("zoned_textNumberPattern_fail02") }
   @Test def testZonedPatternFail03(): Unit = { runner.runOneTest("zoned_textNumberPattern_fail03") }
   @Test def testZonedPatternFail04(): Unit = { runner.runOneTest("zoned_textNumberPattern_fail04") }
+  @Test def testZonedPatternFail05(): Unit = { runner.runOneTest("zoned_textNumberPattern_fail05") }
+  @Test def testZonedPatternFail06(): Unit = { runner.runOneTest("zoned_textNumberPattern_fail06") }
   @Test def testZonedFloatFail01(): Unit = { runner.runOneTest("zoned_float_fail01") }
   @Test def testZonedDoubleFail01(): Unit = { runner.runOneTest("zoned_double_fail01") }
   //TODO: @Test def testZonedEncodingFail01(): Unit = { runner.runOneTest("zoned_encoding_fail01") }