From: Josef 'Jupp' Schugt Date: 2005-03-30T06:10:12+09:00 Subject: Implementing COBOL style number formatting (Was: Any guides for good coding in Ruby?) Hi! From Arfin's question on formatting numbers I conclude that there is a need for a means to precisely control the display of numbers. As long as (natural) science is concerned, printf serves its purpose very well. What seemingly is missing is a powerful commercial number formatting like the one of COBOL. After a small archeological excavation campaign I used some COBOL book to write a first draft of such a formatting. I use the COBOL notation because it has shown its commercial strength for DECADES. Moreover I do not know of any other equally powerful format string language for this kind of application. The EBNF for the full formatting string still needs to be written but that takes some time. Currently planned features: Fixnum#initialize(format, value) Fixnum#to_s(format) Fixnum#decimalPointIsComma Fixnum#decimalPoint Fixnum#groupingCharacter Fixnum#currencySymbol This is EBNF for Fixnum format. PositiveInteger ::= '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'. Integer ::= '0' | PositiveInteger. RepetitionFactor ::= '(' PositiveInteger [Integer+] ')'. DecimalPointPlaceholder ::= 'v'. SignPlaceholder ::= 's'. DigitPlaceholder ::= '9'. DigitsPlaceholder ::= Digitplaceholder+ | Digitplaceholder RepetitionFactor. UnsignedPlaceholder ::= DigitsPlaceholder [ DecimalPointPlaceholder DigitsPlaceholder ]. Fixnum ::= Sign Unsigned. This is EBNF for Fixnum format string. PositiveInteger ::= '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'. Integer ::= '0' | PositiveInteger. RepetitionFactor ::= '(' PositiveInteger [Integer+] ')'. ShowLeadingZero ::= '9'. SuppressedLeadingZero ::= 'Z'. StarLeadingZero ::= '*'. DecimalPoint ::= '.'. GroupingSymbol ::= ','. NegativeSign ::= '-'. AnySign ::= '+'. Blank ::= 'B'. Zero ::= '0'. CurrencySymbol ::= '$'. Credit ::= 'CR'. Debit ::= 'DB'. Slash ::= '/'. '9', 'Z', and '*' are all used to display a digit. They only differn in their handling of leading zeroes. '9' displays any digit as is even if it is a leading zero 'Z' displays any digit as is with the exception of replacing a leading zero by a blank character '.' '*' displays any digit as if with the exception of replacing a leading zero by an asterisk character '*'. '.' displays a 'decimal point' (i.e. the character that separates the integer and fractional part of a number). In many countries this character is indeed a point '.' but in some (e.g. Germany) it is ','[1, 2, 5]. ',' displays a grouping character (i.e. the character that is used to group large numbers). In many countries people tend to use ',', while in other ones '.' is preferred[1, 3, 4, 5]. '-' displays a minus sign '-' for negative numbers and a blank character ' ' otherwise. '+' displays a minus sign '-' for negative numbers and a plus sign '+' otherwise. 'B' displays a blank character ' ' at the given position. '0' displays a zero '0' at the given position '$' displays a currency symbol[6] at the given position 'CR' displays 'CR' in the case of credit (i.e. a value smaller than zero) and two blank characters otherwise. 'DB' displays 'DB' in the case of debit (i.e. a value not smaller than zero) and two blank characters otherwise. '/' displays a slash at the given position. [1] The Boolean decimalPointIsComma property controls the defaults for the decimalPoint[2] and groupingCharacter[3]. It defaults to fixnum.decimalPointIsComma = false [2] The actual character is defined by the decimalPoint property. Default (comments show value of decimalPointIsComma): fixnum.decimalPoint = '.' # false fixnum.decimalPoint = ',' # true The value must be a single character. [3] The actual character is defined by the groupingCharacter property. Defaults (comments show value of decimalPointIsComma): fixnum.groupingCharacter = ',' # false fixnum.groupingCharacter = '.' # true [4] It is strongly recommended NEITHER to use the default setting NOR '.' but a blank character: fixnum.groupingCharacter = ' ' The value must be a single character. [5] If an assignment sets decimalPoint and groupingCharacter to the same character an ArgumentError will be risen. [6] The currency symbol is defined by the currencySymbol property. Default: fixnum.currencySymbol = '$' The currency symbol can be longer than one character. This allows you to use ISO 4217 currency symbols if a given currency symbol is inaccessible (you may e.g. wish to use 'EUR' instead of '€' for euro, 'GBP' instead of '£' for british pound sterling, 'JPY' instead of '¥' for japanese yen, and 'KRW' instead of '₩' for korean won). Comments? Over and out, Josef 'Jupp' Schugt -- Mi estas la releviĝo kaj la vivo; kiu kredas al mi, eĉ se li estos mortinta, tiu vivos, kaj ĉiu, kiu vivas kaj kredas al mi, por ĉiam ne mortos. -- Johaneo 11, 25f