Format Function

Started by Charles Pegge, April 12, 2023, 04:23:59 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Charles Pegge

I'll add this to inc/ParseUtil.inc as it seems to be the most appropriate file.

It supports right-align, left-align, left-trim, leading-spaces, trimmed-decimal, leading-zeros, trailing-zeros, and integers.

function format(double vp, string fp) as string
===============================================
  ' FORMAT STRING EXAMPLES
  ' ####
  ' 0000
  ' L###
  ' T####
  ' T00
  ' ####.##
  ' ####.00
  ' 000.##
  ' 000.000
  '
  string s
  string f=fp
  string sg=" "
  int la
  double v
  int a=asc f
  if a=0x4c then la=1 'L left align with space for '-' sign
  if a=0x54 then la=2 'T left trim
  if la then f=mid(f,2)
  int de=instr(f,".")
  int le=len(f)
  int dp
  int zl
  int zr
  int df
  if asc(f,1)=48 then zl=1
  if de
    df=1
    dp=le-de
    if asc(f,de+1)=48 then zr=1
  endif
  '
  'REJECT E FORMATS
  s=str v
  if instr(s,"E")
    return s
  endif
  '
  'DECIMAL SCALING
  v=round(vp*pow(10,dp))
  s=str v
  '
  'SIGN
  if v<0
    s=mid(s,2)
    sg="-"
  endif
  '
  int ls=len(s)+df
  if ls<le
    string c
    if zl
      c="0"
    else
      c=" "
    endif
    s=string(le-ls,c)+s 'PAD LEFT
  elseif ls>le
    return "?"+str(vp,5) 'SPACE TOO SMALL
  endif
  int i,j
  '
  'DECIMAL FORMATS
  if de
    s=left(s,de-1)+"."+mid(s,de)
    'NAKED POINT
    i=instr(1,s," .")
    if i then mid(s,i)="0"
    '
    'LEADING DECIMAL ZEROS
    i=de
    do
      i=instr(i+1,s," ")
      if i then mid(s,i)="0" : continue do
      exit do
    loop
  endif
  '
  'INSERT SIGN
  i=0
  do
    i++
    j=asc s,i
    if j<>32
      s=left(s,i-1)+sg+mid(s,i)
      exit do
    endif
  loop
  '
  if de<>0 and zr==0
    'REMOVE TRAILING DECIMAL ZEROS
    i=len s
    do
      if i<1 then exit do
      j=asc(s,i)
      if j<>48
        if j=46
          mid(s,i)=" " 'REMOVE DECIMAL POINT
        endif
        exit do
      endif
      mid(s,i)=" " 'REMOVE 0
      i--
    loop
  endif
  '
  'LEFT ALIGN OR TRIM
  if la
    ls=len s
    s=ltrim s
    if sg=" " and la=1
      s=" "+s 'ALLOW SIGN ALIGN
    endif
    j=len s
    s+=space(ls-j)
  endif
  return s
end function

Nicola

Hi Charles,
I tried with this example... is the result right?

double x
x=367.055
Print Format(x, "##.####") 
'result = 367.05500000000001
wait

Charles Pegge

Aha! Format rejected your number because it was too large for the format string. So the number was returned in its ugly and unprocessed form. This is probably a better option than throwing a run-time error. What do you think?

Nicola

Sure, that might be fine, but could it also have just written "367.0550"?

Charles Pegge

If you understand my code you are welcome to fix it :)

Nicola

an idea,
to fix better...

use console

function format(double vp, string fp) as string
===============================================
  ' FORMAT STRING EXAMPLES
  ' ####
  ' 0000
  ' L###
  ' T####
  ' T00
  ' ####.##
  ' ####.00
  ' 000.##
  ' 000.000
  '
int neg
if vp<0 then neg=-1
  string s
  string f=fp
  string ffp=fp
  string sg=" "
  int la
  double v
  int a=asc f
  if a=0x4c then la=1 'L left align with space for '-' sign
  if a=0x54 then la=2 'T left trim
  if la then f=mid(f,2)
  int de=instr(f,".")
  int le=len(f)
  int dp, zl, zr, df
  int i
  if asc(f,1)=48 then zl=1
  if de
    df=1
    dp=le-de
    if asc(f,de+1)=48 then zr=1
  endif
  '
  'REJECT E FORMATS
  s=str v
  if instr(s,"E")
    return s
  endif
  '
  'DECIMAL SCALING
  v=round(vp*pow(10,dp))
  s=str v
  '
  'SIGN
  if v<0
    s=mid(s,2)
    sg="-"
  endif
  '
  int ls=len(s)+df
  if ls<le
    string c
    if zl
      c="0"
    else
      c=" "
    endif
    s=string(le-ls,c)+s 'PAD LEFT
  elseif ls>le
string bb=right(vp,len(vp)-instr(vp,".")) 'parte destra del numero
'printl "bb=" bb
string aa=left(vp, instr(vp,".")-1) 'parte sinistra del numero
'printl "aa=" aa
int lenfp=len(right(ffp,len(ffp)-instr(ffp,".")))
 'int lenbb=len(right(vp,instr(vp,".")))
int lenbb=len(bb)
'printl "lunghezza fp " lenfp
'printl "lunghezza bb " lenbb
'bb=bb & string(lenfp,"0")
 if lenfp>0 then
   if lenbb>lenfp then
     if mid(bb,lenfp+1) > 5 then
       if val(left(bb,lenfp))=val(string(lenfp,"9")) then aa = val((abs(aa) + 1) * neg)
       for i=lenfp to 1 step -1    'verifica per tutta la parte decimale
         int vbl=val(mid(bb,i,1))+1
         'printl vbl
         if vbl>9 then
           mid(bb,i)="0"
else
           mid(bb,i)=str(vbl) : exit for
         end if
        next i
       'end if
      end if
      'bb=right(vp,lenfp)
   end if
 end if 
bb=left(bb,lenfp)
printl bb
printl "numero inserito: " vp
printl "numero formato : " aa "." bb

    return str(vp) 'SPACE TOO SMALL
  endif
  int i,j
  '
  'DECIMAL FORMATS
  if de
    s=left(s,de-1)+"."+mid(s,de)
    'NAKED POINT
    i=instr(1,s," .")
    if i then mid(s,i)="0"
    '
    'LEADING DECIMAL ZEROS
    i=de
    do
      i=instr(i+1,s," ")
      if i then mid(s,i)="0" : continue do
      exit do
    loop
  endif
  '
  'INSERT SIGN
  i=0
  do
    i++
    j=asc s,i
    if j<>32
      s=left(s,i-1)+sg+mid(s,i)
      exit do
    endif
  loop
  '
  if de<>0 and zr==0
    'REMOVE TRAILING DECIMAL ZEROS
    i=len s
    do
      if i<1 then exit do
      j=asc(s,i)
      if j<>48
        if j=46
          mid(s,i)=" " 'REMOVE DECIMAL POINT
        endif
        exit do
      endif
      mid(s,i)=" " 'REMOVE 0
      i--
    loop
  endif
  '
  'LEFT ALIGN OR TRIM
  if la
    ls=len s
    s=ltrim s
    if sg=" " and la=1
      s=" "+s 'ALLOW SIGN ALIGN
    endif
    j=len s
    s+=space(ls-j)
  endif
  return s
end function

double x
x=-368.05516
Printl Format(x, "##.####") 
Printl Format(377.061, "##.####") 
Printl Format(999.09996, "##.####") 
Printl Format(-9.99996, "##.####") 
wait

Charles Pegge

You could do this:

    return "?"+str(vp,5) 'SPACE TOO SMALL

Nicola

#7
I tried to round up to the last digit...

     if mid(bb,lenfp+1) > 5 then
       if val(left(bb,lenfp))=val(string(lenfp,"9")) then aa = val((abs(aa) + 1) * neg)
...

Charles Pegge

We just need something simple that shows clearly in a tabulation, to indicate that the format should be adjusted.

Nicola

Hi Charles,
I put your "format" function in the help, both under Console and under Files.
Cheers

Charles Pegge

Hi Nicola,

I've put the format function into ParseUtil.inc rather than console. (ParseUtil also includes StringUtil). It's a bit volatile since it is not core Oxygen.

Nicola

Ok Charles,
will we have it available in the next update?

Charles Pegge

#12
Yes soon. Not much change to core o2 but I'm reviewing a few of the inc files, and Peter Wirbelauer's window.inc and gdip.inc. There is also Grafide (an extension of Peroxide) which is intended for 3d graphics scripting.

I may also remove LeanLisp because I don't think this genre of coding is going anywhere except backwards in programming history.

Nicola

Hi Charles,
great, we can't wait to have the new version. :)