Author Topic: converting a number to a string, formatted like with "print using"  (Read 1774 times)

0 Members and 1 Guest are viewing this topic.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Quick question (though I am not under the illusion there may be a quick answer! lol).

If you have a numberic variable (Integer, Long, etc.), how might you convert it to a string like with
Code: QB64: [Select]
  1. MyString$ = _Trim$(Str$(MyNumber))
except formatted like wtih
Code: QB64: [Select]
  1. Print Using "###,###,###,###,###,###"; MyNumber
Is there a command for this, or do you just have to write a function to do it?
Example / attempt below. I defined a custom function to format the number.
(Actually, I had to define 3 separate functions for Integer, Long, and _Integer64. So a bonus question: is there a way to do that all with one function?)

Help me, Obi Wan!
Code: QB64: [Select]
  1. ' Question 1: Is there an alternative to Print Using?
  2.  
  3. Dim MyInteger%
  4. Dim MyLong&
  5. Dim My_Integer64&&
  6.  
  7. 'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
  8.  
  9. Print "Attempt to format integer:"
  10. MyInteger% = 32767
  11. Print "MyInteger%=" + _Trim$(Str$(MyInteger%))
  12. Print "FormatInteger$(" + _Trim$(Str$(MyInteger%)) + ") returns " + Chr$(34) + FormatInteger$(MyInteger%) + Chr$(34)
  13. Print Using "MyInteger with PrintUsing: ###,###,###,###,###,###"; MyInteger%
  14. Print "PRESS ANY KEY TO CONTINUE": Sleep
  15.  
  16. MyLong& = 2147483647
  17. Print "MyLong&=" + _Trim$(Str$(MyLong&))
  18. Print "FormatLong$(" + _Trim$(Str$(MyLong&)) + ") returns " + Chr$(34) + FormatLong$(MyLong&) + Chr$(34)
  19. Print Using "MyLong with PrintUsing: ###,###,###,###,###,###"; MyLong&
  20. Print "PRESS ANY KEY TO CONTINUE": Sleep
  21.  
  22. My_Integer64&& = 9223372036854775807
  23. Print "My_Integer64&&=" + _Trim$(Str$(My_Integer64&&))
  24. Print "Format_Integer64$(" + _Trim$(Str$(My_Integer64&&)) + ") returns " + Chr$(34) + Format_Integer64$(My_Integer64&&) + Chr$(34)
  25. Print Using "My_Integer64 with PrintUsing: ###,###,###,###,###,###,###"; My_Integer64&&
  26. Print "PRESS ANY KEY TO CONTINUE": Sleep
  27.  
  28. 'Screen 0
  29.  
  30. ' Question 2 (BONUS): Is there a way to define just one function that receives
  31. '                     a variant (like in VB6/VBA) so you don't have to define
  32. '                     seperate nearly identical functions for each type?
  33.  
  34. Function FormatInteger$ (MyValue%)
  35.     Dim StringValue$: StringValue$ = ""
  36.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue%))
  37.     Dim iLoop As Long
  38.     Dim iCount As Integer: iCount = 0
  39.     'Print "TempString$=" + TempString$
  40.     For iLoop = Len(TempString$) To 1 Step -1
  41.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  42.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  43.     Next iLoop
  44.     FormatInteger$ = StringValue$
  45. End Function ' FormatInteger$
  46.  
  47. Function FormatLong$ (MyValue&)
  48.     Dim StringValue$: StringValue$ = ""
  49.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue&))
  50.     Dim iLoop As Long
  51.     Dim iCount As Integer: iCount = 0
  52.     'Print "TempString$=" + TempString$
  53.     For iLoop = Len(TempString$) To 1 Step -1
  54.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  55.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  56.     Next iLoop
  57.     FormatLong$ = StringValue$
  58. End Function ' FormatLong$
  59.  
  60. Function Format_Integer64$ (MyValue&&)
  61.     Dim StringValue$: StringValue$ = ""
  62.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue&&))
  63.     Dim iLoop As Long
  64.     Dim iCount As Integer: iCount = 0
  65.     'Print "TempString$=" + TempString$
  66.     For iLoop = Len(TempString$) To 1 Step -1
  67.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  68.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  69.     Next iLoop
  70.     Format_Integer64$ = StringValue$
  71. End Function ' Format_Integer64$
  72.  
« Last Edit: March 05, 2022, 12:17:00 pm by madscijr »

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
Re: converting a number to a string, formatted like with "print using"
« Reply #1 on: March 05, 2022, 12:33:52 pm »
Anwer to question 1: yes

Code: QB64: [Select]
  1. 'number as is
  2. PRINT IndexFormat$("MyInteger% = 0{R}", STR$(32767), "~")
  3. 'number with thousands separator ,
  4. PRINT IndexFormat$("MyInteger% = 0{#####,}", STR$(32767), "~")
  5. 'number with thousands separator flipped to .
  6. PRINT IndexFormat$("MyInteger% = 0{?,:#####,}", STR$(32767), "~")
  7. 'number as grouped Hex/Oct/Bin
  8. PRINT IndexFormat$("MyInteger% = 0{?2:H8}", STR$(32767), "~")
  9. PRINT IndexFormat$("MyInteger% = 0{?4:O8}", STR$(32767), "~")
  10. PRINT IndexFormat$("MyInteger% = 0{?4:B16}", STR$(32767), "~")
  11.  
  12. 'insert FUNCTION IndexFormat$ here, get it from:
  13. 'https://qb64forum.alephc.xyz/index.php?topic=2932.msg121898#msg121898
  14. '(7z inclusive example and docs)
  15.  
  16.  

Answer to question 2: not familiar with VB6/VBA, sorry
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #2 on: March 05, 2022, 01:05:18 pm »
Anwer to question 1: yes
...
Answer to question 2: not familiar with VB6/VBA, sorry

Thanks for your reply.

Re: question 2
Point is, other than the input parameters, the 3 functions in my example are identical. So, instead of having to make a separate function for every parameter type, is there a way to just make _one_ general purpose function, where the parameter can be _any_ type? In VBA there is a type called Variant which means it can hold any type you put in it (and in JavaScript and Python, there are no type declarations, ALL variables are "variants", which I think is insane, but that's another discussion). In those languages, you can just declare one function, where the input is of type Variant, meaning it can receive any type, and then inside the function, if need be, you can type check and handle the input differently (or not). Kabish?

Anyway, thank you for your reply and explaining how to set a string variable formatted like Print Using does.

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
Re: converting a number to a string, formatted like with "print using"
« Reply #3 on: March 05, 2022, 04:49:33 pm »
Ah, so you talk about function overloading. Not possible in QB64 as is, but look on IndexFormat$, it's a function which needs to handle several different arguments/types too, it takes all the different parameters in the argument string, all added together, strings as is, numbers via STR$(). Then, inside the functions you need to parse that whole argument string to get what you need.

Another way would be a user defined type:
Code: QB64: [Select]
  1. Type aNumber
  2.     typ AS STRING * 3
  3.     n8 AS _BYTE
  4.     n16 AS INTEGER
  5.     n32 AS LONG
  6.     n64 AS _INTEGER64
  7.     ns AS SINGLE
  8.     nd AS DOUBLE
  9.     nf AS _FLOAT
  10.  
  11. DIM num AS aNumber
  12. num.typ = "n16"
  13. num.n16 = 32767
  14. res = DoSomthingWithNumber(num)
  15.  
  16. FUNCTION DoSomthingWithNumber (x AS aNumber)
  17.     CASE "n8"
  18.         'do _BYTE stuff here
  19.     CASE "n16"
  20.         'do INTEGER stuff here
  21.     CASE "n32"
  22.         'do LONG stuff here
  23.     CASE "n64"
  24.         'do _INTEGER64 stuff here
  25.     CASE "ns"
  26.         'do SINGLE stuff here
  27.     CASE "nd"
  28.         'do DOUBLE stuff here
  29.     CASE "nf"
  30.         'do _FLOAT stuff here
  31.  
  32.  
As you can see, there are multiple ways to build universal functions, but unfortunately no such easy thing like a 'variants" type. Somewhere you have to go in and do your own coding.

Guess @SMcNeill could also show you a variant doing this with _MEM variables. He made a universal QuickSort function somewhere here in the forum, using _MEM variables to determine the array type which is to be sorted in his function.

EDIT:
here's the _MEM sort, maybe you can derive something useful for your needs...
https://qb64forum.alephc.xyz/index.php?topic=1601.0
« Last Edit: March 05, 2022, 04:55:02 pm by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #4 on: March 05, 2022, 06:03:50 pm »
Ah, so you talk about function overloading. Not possible in QB64 as is, but look on IndexFormat$, it's a function which needs to handle several different arguments/types too,
...
Guess @SMcNeill could also show you a variant doing this with _MEM variables. He made a universal QuickSort function somewhere here in the forum, using _MEM variables to determine the array type which is to be sorted in his function.
EDIT:
here's the _MEM sort, maybe you can derive something useful for your needs...
https://qb64forum.alephc.xyz/index.php?topic=1601.0

Good to know - thanks!
I guess the convenience of only having one function has to be weighed against the performance hit of unpacking/converting the input into the needed type, type checking, etc.
I will definitely play with your examples, thanks again.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: converting a number to a string, formatted like with "print using"
« Reply #5 on: March 05, 2022, 08:00:10 pm »
Seems like Double parameter can handle various Types:
Code: QB64: [Select]
  1. Dim i%
  2. i% = 100000 * Rnd - 50000
  3. Print commaD$(i%, 2)
  4. j& = 10000000 * Rnd - 5000000
  5. Print commaD$(j&, 2)
  6. k## = 100000 * Rnd - 50000
  7. Print commaD$(k##, 4)
  8.  
  9. Function commaD$ (n#, nDecPlaces%) 'only works right for double# type
  10.     Dim place As Long, s$, front$, back$, func$
  11.     func$ = _Trim$(Str$(n#))
  12.     If Left$(func$, 1) = "-" Then s$ = "-": func$ = Mid$(func$, 2) Else s$ = ""
  13.     place = InStr(func$, ".")
  14.     If place = 0 Then place = Len(func$) + 1
  15.     While place > 4
  16.         func$ = Mid$(func$, 1, place - 4) + "," + Mid$(func$, place - 3)
  17.         place = InStr(func$, ",")
  18.     Wend
  19.     'fix to nDecPlaces
  20.     place = InStr(func$, ".")
  21.     If nDecPlaces% Then
  22.         If place Then
  23.             front$ = Mid$(func$, 1, place)
  24.             back$ = Mid$(func$, place + 1)
  25.             If Len(back$) > nDecPlaces% Then func$ = front$ + Left$(back$, nDecPlaces%)
  26.             If Len(back$) < nDecPlaces% Then func$ = front$ + Left$(back$ + String$(nDecPlaces%, "0"), nDecPlaces%)
  27.         Else
  28.             func$ = func$ + "." + String$(nDecPlaces%, "0")
  29.         End If
  30.     Else
  31.         If place Then func$ = Mid$(func$, 1, place - 1)
  32.     End If
  33.     commaD$ = s$ + func$
  34.  
  35.  

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: converting a number to a string, formatted like with "print using"
« Reply #6 on: March 05, 2022, 10:26:57 pm »
Try something like this:

Code: QB64: [Select]
  1. Print "FOO: "; format$("###.###", "123.456789")
  2. Print format$("###,.##", "123456789.987654321")
  3.  
  4.  
  5. Function format$ (template As String, text As String)
  6.     d = _Dest: s = _Source
  7.     n = _NewImage(80, 80, 0)
  8.     _Dest n: _Source n
  9.     Print Using template; Val(text)
  10.     For i = 1 To 79
  11.         t$ = t$ + Chr$(Screen(1, i))
  12.     Next
  13.     If Left$(t$, 1) = "%" Then t$ = Mid$(t$, 2)
  14.     format$ = _Trim$(t$)
  15.     _Dest d: _Source s
  16.     _FreeImage n

Pass it the same format string you'd use with PRINT USING, and then the STR$ value of your number.  It'll return a string formatted just as PRINT USING would do.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: converting a number to a string, formatted like with "print using"
« Reply #7 on: March 06, 2022, 11:52:41 am »
Try something like this:

Code: QB64: [Select]
  1. Print "FOO: "; format$("###.###", "123.456789")
  2. Print format$("###,.##", "123456789.987654321")
  3.  
  4.  
  5. Function format$ (template As String, text As String)
  6.     d = _Dest: s = _Source
  7.     n = _NewImage(80, 80, 0)
  8.     _Dest n: _Source n
  9.     Print Using template; Val(text)
  10.     For i = 1 To 79
  11.         t$ = t$ + Chr$(Screen(1, i))
  12.     Next
  13.     If Left$(t$, 1) = "%" Then t$ = Mid$(t$, 2)
  14.     format$ = _Trim$(t$)
  15.     _Dest d: _Source s
  16.     _FreeImage n

Pass it the same format string you'd use with PRINT USING, and then the STR$ value of your number.  It'll return a string formatted just as PRINT USING would do.

Oh! that looks like it gets around the Type problem.
 n = _NewImage(80, 80, 0)
0 the one mode you can read characters from, a point for Pete ;-))

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
Re: converting a number to a string, formatted like with "print using"
« Reply #8 on: March 14, 2022, 08:52:16 am »
Try something like this:

Code: QB64: [Select]
  1. Print "FOO: "; format$("###.###", "123.456789")
  2. Print format$("###,.##", "123456789.987654321")
  3.  
  4.  
  5. Function format$ (template As String, text As String)
  6.     d = _Dest: s = _Source
  7.     n = _NewImage(80, 80, 0)
  8.     _Dest n: _Source n
  9.     Print Using template; Val(text)
  10.     For i = 1 To 79
  11.         t$ = t$ + Chr$(Screen(1, i))
  12.     Next
  13.     If Left$(t$, 1) = "%" Then t$ = Mid$(t$, 2)
  14.     format$ = _Trim$(t$)
  15.     _Dest d: _Source s
  16.     _FreeImage n

Pass it the same format string you'd use with PRINT USING, and then the STR$ value of your number.  It'll return a string formatted just as PRINT USING would do.

Very original, simple and effective

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #9 on: March 14, 2022, 12:57:56 pm »
Thanks everyone for your replies. I have been away on spring break, so have some catching up to do. I will gove
this all a look and try out the various examples as soon as I can get to it. Thanks again!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #10 on: March 18, 2022, 09:01:38 am »
I played around with the examples, so far so good but I have run out of time for today.
Here is everything in one handy dandy test program...
Code: QB64: [Select]
  1. ' Formatting numbers (alternatives to Print using)
  2. ' https://qb64forum.alephc.xyz/index.php?topic=4703.msg141127#msg141127
  3.  
  4. ' BOOLEAN VALUES
  5. Const FALSE = 0
  6. Const TRUE = Not FALSE
  7.  
  8. ' Used by RhoSigma's operator overloading workaround example:
  9. Type aNumber
  10.     typ As String * 3
  11.     n8 As _Byte
  12.     n16 As Integer
  13.     n32 As Long
  14.     n64 As _Integer64
  15.     ns As Single
  16.     nd As Double
  17.     nf As _Float
  18. End Type ' aNumber
  19.  
  20. ' Global variables
  21. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  22. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  23.  
  24. ' Start main menu
  25. main
  26.  
  27. ' Exit program
  28. 'Screen 0
  29.  
  30. ' /////////////////////////////////////////////////////////////////////////////
  31.  
  32. Sub main
  33.     Dim RoutineName As String: RoutineName = "main"
  34.     Dim in$
  35.     Dim bFinished As Integer: bFinished = FALSE
  36.     Dim result$: result$ = ""
  37.     Do
  38.         Screen 0: _ScreenMove 0, 0
  39.         Cls
  40.         Print m_ProgramName$
  41.         Print
  42.         Print "converting a number to a string, formatted like with 'print using'"
  43.         Print
  44.  
  45.         Print "1) Format Numbers Manually (parse string, insert commas)"
  46.         Print "2) IndexFormat$ by RhoSigma example #1"
  47.         Print "3) IndexFormat$ by RhoSigma example #2"
  48.         Print "4) commaD$ by bplus"
  49.         Print "5) format$ by SMcNeill"
  50.         Print
  51.         Print "Q) Exit program"
  52.  
  53.         Do
  54.             in$ = InKey$
  55.             If UCase$(in$) = "Q" Then
  56.                 bFinished = TRUE: Exit Do
  57.             ElseIf UCase$(in$) = "1" Then
  58.                 FormatNumbersManually: Exit Do
  59.             ElseIf UCase$(in$) = "2" Then
  60.                 IndexFormatTest1: Exit Do
  61.             ElseIf UCase$(in$) = "3" Then
  62.                 IndexFormatTest2: Exit Do
  63.             ElseIf UCase$(in$) = "4" Then
  64.                 commaD_Test: Exit Do
  65.             ElseIf UCase$(in$) = "5" Then
  66.                 FormatStringTest: Exit Do
  67.             End If
  68.         Loop
  69.     Loop Until bFinished = TRUE
  70. End Sub ' main
  71.  
  72. ' /////////////////////////////////////////////////////////////////////////////
  73. ' Question 1: Is there an alternative to Print Using?
  74.  
  75. ' Answer 1: Format numbers the manual way!
  76.  
  77. Sub FormatNumbersManually
  78.     Dim MyInteger%
  79.     Dim MyLong&
  80.     Dim My_Integer64&&
  81.  
  82.     'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
  83.     'Cls
  84.  
  85.     Print "-------------------------------------------------------------------------------"
  86.     Print "Format numbers (add commas) by manually parsing the string:"
  87.     Print
  88.  
  89.     Print "Attempt to format integer:"
  90.     MyInteger% = 32767
  91.     Print "MyInteger%=" + _Trim$(Str$(MyInteger%))
  92.     Print "FormatInteger$(" + _Trim$(Str$(MyInteger%)) + ") returns " + Chr$(34) + FormatInteger$(MyInteger%) + Chr$(34)
  93.     Print Using "MyInteger with PrintUsing: ###,###,###,###,###,###"; MyInteger%
  94.     Print
  95.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  96.  
  97.     MyLong& = 2147483647
  98.     Print "MyLong&=" + _Trim$(Str$(MyLong&))
  99.     Print "FormatLong$(" + _Trim$(Str$(MyLong&)) + ") returns " + Chr$(34) + FormatLong$(MyLong&) + Chr$(34)
  100.     Print Using "MyLong with PrintUsing: ###,###,###,###,###,###"; MyLong&
  101.     Print
  102.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  103.  
  104.     My_Integer64&& = 9223372036854775807
  105.     Print "My_Integer64&&=" + _Trim$(Str$(My_Integer64&&))
  106.     Print "Format_Integer64$(" + _Trim$(Str$(My_Integer64&&)) + ") returns " + Chr$(34) + Format_Integer64$(My_Integer64&&) + Chr$(34)
  107.     Print Using "My_Integer64 with PrintUsing: ###,###,###,###,###,###,###"; My_Integer64&&
  108.     Print
  109.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  110.  
  111.     Print "-------------------------------------------------------------------------------"
  112. End Sub ' FormatNumbersManually
  113.  
  114. ' Question 2 (BONUS): Is there a way to define just one function that receives
  115. '                     a variant (like in VB6/VBA) so you don't have to define
  116. '                     seperate nearly identical functions for each type?
  117.  
  118. Function FormatInteger$ (MyValue%)
  119.     Dim StringValue$: StringValue$ = ""
  120.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue%))
  121.     Dim iLoop As Long
  122.     Dim iCount As Integer: iCount = 0
  123.     'Print "TempString$=" + TempString$
  124.     For iLoop = Len(TempString$) To 1 Step -1
  125.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  126.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  127.     Next iLoop
  128.     FormatInteger$ = StringValue$
  129. End Function ' FormatInteger$
  130.  
  131. Function FormatLong$ (MyValue&)
  132.     Dim StringValue$: StringValue$ = ""
  133.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue&))
  134.     Dim iLoop As Long
  135.     Dim iCount As Integer: iCount = 0
  136.     'Print "TempString$=" + TempString$
  137.     For iLoop = Len(TempString$) To 1 Step -1
  138.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  139.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  140.     Next iLoop
  141.     FormatLong$ = StringValue$
  142. End Function ' FormatLong$
  143.  
  144. Function Format_Integer64$ (MyValue&&)
  145.     Dim StringValue$: StringValue$ = ""
  146.     Dim TempString$: TempString$ = _Trim$(Str$(MyValue&&))
  147.     Dim iLoop As Long
  148.     Dim iCount As Integer: iCount = 0
  149.     'Print "TempString$=" + TempString$
  150.     For iLoop = Len(TempString$) To 1 Step -1
  151.         iCount = iCount + 1: If iCount > 3 Then StringValue$ = "," + StringValue$: iCount = 1 ': Print "added comma: " + StringValue$
  152.         StringValue$ = Mid$(TempString$, iLoop, 1) + StringValue$ ': Print "next value: " + StringValue$
  153.     Next iLoop
  154.     Format_Integer64$ = StringValue$
  155. End Function ' Format_Integer64$
  156.  
  157. ' /////////////////////////////////////////////////////////////////////////////
  158. ' Format$ function with indexed & reusable arguments by RhoSigma
  159. ' https://qb64forum.alephc.xyz/index.php?topic=2932.msg121898#msg121898
  160.  
  161. ' As the title says,
  162. ' this is a Format$ function (PRINT USING style), which allows for explicit
  163. ' argument indexing in the given format template. The indexing feature lets
  164. ' you change the template being processed while keeping the arguments stream
  165. ' the same.
  166.  
  167. ' This can be an invaluable tool in some situations, just think about
  168. ' different date formats. With PRINT USING alone you would probably need to
  169. ' reorder your day, month, year, weekday etc. arguments for every date format
  170. ' to match the order of the respective format tokens in the template, but not
  171. ' so with this function. Another example is when it comes to localizing your
  172. ' programs, where it helps when translating template strings to different
  173. ' languages and the sentence structure and thus the order of the arguments
  174. ' changes.
  175.  
  176. ' Beside the indexing, which this function got its name from, it has a couple
  177. ' other useful extensions compared to the regular PRINT USING conventions,
  178. ' such as bin/hex/oct formatting, use of escape sequences to insert control
  179. ' or extended ASCII chars and more. All of this is detailed in the
  180. ' comprehensive HTML Documentation available for download below the example
  181. ' code block.
  182.  
  183. ' As it is required to preserve the UTF-8 encoding of the HTML Documentation
  184. ' and some preformatted examples, it is packed into an 7-zip archive file
  185. ' attached below. The archive does also contain the example from the codebox
  186. ' above.
  187.  
  188. '--- Full description available in separate HTML document.
  189.  
  190. ' My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
  191. ' GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
  192. ' Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
  193. ' Bonus - Blankers, QB64/Notepad++ setup pack
  194.  
  195. Function IndexFormat$ (fmt$, arg$, sep$)
  196.     '--- option _explicit requirements ---
  197.     Dim args$, shan&, dhan&, than&, idx%, cpos&, res$, lit%, tok%, ft$, cch$
  198.     Dim och$, opos&, tmp$, fp$, tyl%, typ$, oval&&, temp~&&, curr%, high%
  199.     '--- init ---
  200.     args$ = arg$ 'avoid side effects
  201.     shan& = _Source: dhan& = _Dest: than& = _NewImage(256, 1, 0)
  202.     _Source than&: _Dest than&
  203.     ReDim argArr$(0 To 35) 'all args empty
  204.     '--- parse arguments ---
  205.     If Right$(args$, Len(sep$)) <> sep$ Then args$ = args$ + sep$
  206.     For idx% = 0 To 35
  207.         cpos& = InStr(args$, sep$): If cpos& = 0 Then Exit For
  208.         argArr$(idx%) = Left$(args$, cpos& - 1)
  209.         args$ = Mid$(args$, cpos& + Len(sep$))
  210.     Next idx%
  211.     '--- process format template ---
  212.     res$ = "": lit% = 0: tok% = 0: ft$ = "": idx% = -1
  213.     For cpos& = 1 To Len(fmt$)
  214.         cch$ = Mid$(fmt$, cpos&, 1)
  215.         If cch$ = "_" And lit% = 0 Then 'take next \{} as literal
  216.             If Not tok% Then lit% = -1
  217.         ElseIf cch$ = "\" And lit% = 0 And tok% = 0 Then 'insert esc sequence
  218.             If cpos& < Len(fmt$) Then
  219.                 Select Case UCase$(Mid$(fmt$, cpos& + 1, 1))
  220.                     Case "A": och$ = Chr$(7) ' audio bell
  221.                     Case "B": och$ = Chr$(8) ' backspace
  222.                     Case "T": och$ = Chr$(9) ' tabulator
  223.                     Case "N": och$ = Chr$(10) 'line feed
  224.                     Case "V": och$ = Chr$(11) 'vertical tabulator
  225.                     Case "F": och$ = Chr$(12) 'form feed
  226.                     Case "R": och$ = Chr$(13) 'carriage return
  227.                     Case "E": och$ = Chr$(27) 'escape
  228.                     Case "0", "1", "2", "3" '  octal ASCII (3 digits)
  229.                         och$ = Chr$(Val("&O" + Mid$(fmt$, cpos& + 1, 3)))
  230.                         cpos& = cpos& + 2
  231.                     Case "X" '                 hex ASCII (x + 2 digits)
  232.                         och$ = Chr$(Val("&H" + Mid$(fmt$, cpos& + 2, 2)))
  233.                         cpos& = cpos& + 2
  234.                     Case Else: och$ = "" '     ignore unknowns
  235.                 End Select
  236.                 res$ = res$ + och$
  237.                 cpos& = cpos& + 1: opos& = cpos&
  238.             End If
  239.         ElseIf cch$ = "{" And lit% = 0 Then 'begin of formatting token
  240.             If idx% = -1 Then
  241.                 och$ = UCase$(Mid$(fmt$, cpos& - 1, 1)): tok% = -1
  242.                 If ((cpos& - 1) = opos&) Or ((och$ < "0" Or och$ > "9") And (och$ < "A" Or och$ > "Z")) Then och$ = "-"
  243.                 If och$ = "-" Then och$ = "0": Else res$ = Left$(res$, Len(res$) - 1)
  244.                 If och$ >= "A" Then idx% = Asc(och$) - 55: Else idx% = Val(och$)
  245.             End If
  246.         ElseIf cch$ = "}" And lit% = 0 Then 'end of formatting token
  247.             If idx% >= 0 Then
  248.                 GoSub doArgFormat: res$ = res$ + tmp$
  249.                 tok% = 0: ft$ = "": idx% = -1
  250.             End If
  251.         Else 'accumulate chars/symbols in correct channel
  252.             If lit% And InStr("\{}", cch$) = 0 Then cch$ = "_" + cch$
  253.             If tok% Then ft$ = ft$ + cch$: Else res$ = res$ + cch$
  254.             lit% = 0
  255.         End If
  256.     Next cpos&
  257.     '--- cleanup & set result ---
  258.     Erase argArr$
  259.     _Source shan&: _Dest dhan&: _FreeImage than&
  260.     IndexFormat$ = res$
  261.     '-----------------------------
  262.     doArgFormat:
  263.     'Cls:
  264.     tmp$ = "": fp$ = "": ft$ = LTrim$(RTrim$(ft$))
  265.     If Left$(ft$, 1) = "?" Then
  266.         tyl% = InStr(2, ft$, ":")
  267.         If tyl% > 0 Then fp$ = Left$(Mid$(ft$, 2, tyl% - 2), 2): ft$ = LTrim$(Mid$(ft$, tyl% + 1)) 'extract format prefs
  268.     End If
  269.     If ft$ = "" Then Return 'empty token = empty formatted
  270.     Select Case UCase$(Left$(ft$, 1))
  271.         Case "!", "&", "\" 'regular string formatting
  272.             If Left$(ft$, 1) = "\" Then
  273.                 tyl% = InStr(2, ft$, "\"): If tyl% = 0 Then ft$ = "\" + ft$: tyl% = 2
  274.                 If LTrim$(fp$) <> "" And Len(argArr$(idx%)) < tyl% Then
  275.                     Select Case Left$(LTrim$(fp$), 1)
  276.                         Case "C", "c": tyl% = (tyl% - Len(argArr$(idx%))) \ 2
  277.                         Case "R", "r": tyl% = tyl% - Len(argArr$(idx%))
  278.                         Case Else: tyl% = 0 'L or Unknown is default (left)
  279.                     End Select
  280.                     argArr$(idx%) = Space$(tyl%) + argArr$(idx%)
  281.                 End If
  282.             End If
  283.             Print Using ft$; argArr$(idx%);: fp$ = ""
  284.         Case "B", "D", "H", "O", "R" 'extended number formatting (bin/dec/hex/oct/real)
  285.             typ$ = Left$(ft$, 1): tyl% = Val(Mid$(ft$, 2))
  286.             Select Case typ$
  287.                 Case "B", "b": GoSub doBinString
  288.                 Case "D", "d": tmp$ = LTrim$(Str$(_Round(Val(argArr$(idx%)))))
  289.                 Case "H", "h"
  290.                     tmp$ = Hex$(Val(argArr$(idx%)))
  291.                     If typ$ = "H" Then tmp$ = UCase$(tmp$): Else tmp$ = LCase$(tmp$)
  292.                 Case "O", "o": tmp$ = Oct$(Val(argArr$(idx%)))
  293.                 Case "R", "r": tmp$ = LTrim$(Str$(Val(argArr$(idx%)))): fp$ = ""
  294.             End Select
  295.             If tyl% > 0 Then 'adjust field length (if any)
  296.                 If Len(tmp$) <= tyl% Then
  297.                     tmp$ = Right$(String$(tyl%, "0") + tmp$, tyl%): idx% = InStr(tmp$, "-")
  298.                     If idx% > 0 Then
  299.                         typ$ = UCase$(Mid$(tmp$, idx% - 1, 1))
  300.                         If typ$ <> "E" And typ$ <> "D" Then tmp$ = "-" + Left$(tmp$, idx% - 1) + Mid$(tmp$, idx% + 1)
  301.                     End If
  302.                 Else
  303.                     tmp$ = "%" + tmp$
  304.                 End If
  305.             End If
  306.             If LTrim$(fp$) <> "" Then 'apply grouping (if any)
  307.                 typ$ = "": tyl% = 0
  308.                 For idx% = Len(tmp$) To 1 Step -1
  309.                     typ$ = Mid$(tmp$, idx%, 1) + typ$: tyl% = tyl% + 1
  310.                     If tyl% = Val(fp$) Then typ$ = " " + typ$: tyl% = 0
  311.                 Next idx%
  312.                 tmp$ = LTrim$(typ$): If Left$(tmp$, 2) = "- " Then tmp$ = "-" + Mid$(tmp$, 3)
  313.             End If
  314.             Return
  315.         Case Else 'regular number formatting (or invalid nonsense)
  316.             If InStr(ft$, "**") = 0 And InStr(ft$, "$$") = 0 And InStr(ft$, "#") = 0 Then
  317.                 Print ft$; 'take nonsense as is
  318.             Else
  319.                 Print Using ft$; Val(argArr$(idx%));
  320.             End If
  321.     End Select
  322.     tyl% = InStr(fp$, ","): If tyl% > 0 Then Mid$(fp$, tyl%, 1) = " "
  323.     fp$ = LTrim$(RTrim$(fp$))
  324.     For idx% = 1 To Pos(0) - 1
  325.         typ$ = Chr$(Screen(1, idx%)): ft$ = typ$
  326.         If fp$ <> "" And typ$ = "$" Then ft$ = fp$
  327.         If tyl% > 0 And typ$ = "," Then ft$ = "."
  328.         If tyl% > 0 And typ$ = "." Then ft$ = ","
  329.         tmp$ = tmp$ + ft$
  330.     Next idx%
  331.     Return
  332.     '-----------------------------
  333.     doBinString:
  334.     oval&& = Val(argArr$(idx%)): temp~&& = oval&&
  335.     tmp$ = String$(64, "0"): curr% = 64: high% = 64
  336.     Do
  337.         If (temp~&& And 1) Then Asc(tmp$, curr%) = 49: high% = curr%
  338.         curr% = curr% - 1: temp~&& = temp~&& \ 2
  339.     Loop Until temp~&& = 0
  340.     If oval&& < 0 Then
  341.         If -oval&& < &H0080000000~&& Then high% = 33
  342.         If -oval&& < &H0000008000~&& Then high% = 49
  343.         If -oval&& < &H0000000080~&& Then high% = 57
  344.     End If
  345.     tmp$ = Mid$(tmp$, high%)
  346.     Return
  347. End Function ' IndexFormat$
  348.  
  349. ' An example using the new IndexFormat function:
  350. ' Save as: FormatExample.bas (or whatever)
  351.  
  352. Sub IndexFormatTest1
  353.     Dim RoutineName As String: RoutineName = "Example of IndexFormat$ by RhoSigma"
  354.  
  355.     '_Title "FormatExample"
  356.  
  357.     '=== Full description for the IndexFormat$() function is available
  358.     '=== in the separate HTML document.
  359.     '=====================================================================
  360.     'Width , 30
  361.  
  362.     '-- The following format templates need its arguments in different order,
  363.     '-- no problem with indexing, no need to reorder the given arguments.
  364.     '-- You may even use different formatting for the same argument, as long
  365.     '-- as its types are compatible (ie. string vs. number).
  366.     dateDE$ = "Date format Germany: 0{#}. 1{&} 2{####}" ' 1{} = full string
  367.     dateUS$ = "Date format US     : 1{\ \}/0{#} 2{####}" '1{} = first 3 chars only
  368.  
  369.     '-- The easiest way to pass a variable number of arguments, which may
  370.     '-- even be of different types, to a user function is using a string.
  371.     '-- All arguments will be concatenated in this string, separated by a
  372.     '-- designated char/string which does not appear in the arguments itself.
  373.     '-- Strings can be added as is, numbers can be added as literal strings
  374.     '-- too, or in the form STR$(variable).
  375.     year% = 2021
  376.     argStr$ = "2|Januar|" + Str$(year%)
  377.     '-- In this example the | is the argument separator. Use whatever is
  378.     '-- suitable for your needs, maybe even a CHR$(0).
  379.  
  380.     '-- Now let's test the whole thing, we've different token orders in the
  381.     '-- format templates, but use the same argument string for both calls.
  382.     Cls: Print RoutineName: Print
  383.     Print "DATE FORMATTING:"
  384.     Print "dateDE$=" + Chr$(34) + IndexFormat$(dateDE$, argStr$, "|") + Chr$(34)
  385.     Print "dateUS$=" + Chr$(34) + IndexFormat$(dateUS$, argStr$, "|") + Chr$(34)
  386.     Print
  387.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  388.  
  389.     '-- And here the examples from the function description, which also
  390.     '-- shows the reuse of arguments without the need to pass more arguments
  391.     '-- for the additional "feet" and "toes" format tokens.
  392.     head = 1: hands = 2: fingers = 10
  393.     Cls: Print RoutineName: Print
  394.     Print "WITH PRINT USING:"
  395.     Print Using "## head, ## hands and ## fingers"; head, hands, fingers
  396.     Print Using "## fingers, ## head and ## hands"; head, hands, fingers
  397.  
  398.     Print
  399.     Print "WITH IndexFormat$:"
  400.     argStr$ = Str$(head) + "|" + Str$(hands) + "|" + Str$(fingers)
  401.     Print IndexFormat$("2{##} fingers, 0{##} head and 1{##} hands", argStr$, "|")
  402.     Print
  403.     Print IndexFormat$("0{##} head, 1{##} hands and 2{##} fingers, also 1{##} feet and 2{##} toes", argStr$, "|")
  404.     Print
  405.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  406.  
  407.     '-- The function can also handle escape sequences as known from C/C++,
  408.     '-- so you may use those sequences within your format templates.
  409.     Cls: Print RoutineName: Print
  410.     Print "EXAMPLE OF ESCAPE SEQUENCES:"
  411.     Print
  412.     Print IndexFormat$("Column-1\tColumn-2\tColumn-3\n0{#.##}\t\t1{#.##}\t\t2{#.##}", "1.11|2.22|3.33", "|")
  413.     Print
  414.     Print IndexFormat$("This is a \x220{&}\x22 section.", "quoted", "|")
  415.     Print
  416.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  417.  
  418.     Cls: Print RoutineName: Print
  419.     Print "EXAMPLE OF ESCAPE SEQUENCES and the new bin/dec/hex/oct/real formatting:"
  420.     '-- Using escape sequences and the new bin/dec/hex/oct/real formatting,
  421.     '-- while reusing the same argument for all tokens. Also showing the use
  422.     '-- of preferences specifiers to group bin and hex outputs.
  423.     Print IndexFormat$(" Bin: 0{?4:B16}\n Dec: 0{D}\n Hex: 0{?2:H8}\n Oct: 0{O}\nReal: 0{R}\n", "2021.00548", "|")
  424.     Print
  425.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  426.  
  427.     '-- Alignment of strings in a fixed length field, the square brackets are
  428.     '-- just used to better visualize the field.
  429.     Cls: Print RoutineName: Print
  430.     Print "ALIGNMENT OF STRINGS:"
  431.     Print IndexFormat$("[0{?L:\             \}]", "RhoSigma", "|")
  432.     Print IndexFormat$("[0{?C:\             \}]", "RhoSigma", "|")
  433.     Print IndexFormat$("[0{?R:\             \}]", "RhoSigma", "|")
  434.     Print
  435.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  436.  
  437.     '-- Finally a currency example with replaced dollar sign and flipped
  438.     '-- comma/dot notation. I'd like to get that much for this function ;)
  439.     Cls: Print RoutineName: Print
  440.     Print "CURRENCY EXAMPLE:"
  441.     Print IndexFormat$("Account balance: 0{?î,:**$#####,.##}", "12345.67", "|")
  442.     Print
  443.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  444. End Sub ' IndexFormatTest1
  445.  
  446. ' /////////////////////////////////////////////////////////////////////////////
  447. 'insert FUNCTION IndexFormat$ here, get it from:
  448. 'https://qb64forum.alephc.xyz/index.php?topic=2932.msg121898#msg121898
  449. '(7z inclusive example and docs)
  450.  
  451. Sub IndexFormatTest2
  452.     Print "-------------------------------------------------------------------------------"
  453.     Print "IndexFormat$ by RhoSigma:"
  454.     Print
  455.  
  456.     Print "number as is:"
  457.     Print IndexFormat$("MyInteger% = 0{R}", Str$(32767), "~")
  458.     Print "number with thousands separator:"
  459.     Print IndexFormat$("MyInteger% = 0{#####,}", Str$(32767), "~")
  460.     Print "number with thousands separator flipped to:"
  461.     Print IndexFormat$("MyInteger% = 0{?,:#####,}", Str$(32767), "~")
  462.     Print "number as grouped Hex/Oct/Bin:"
  463.     Print IndexFormat$("MyInteger% = 0{?2:H8}", Str$(32767), "~")
  464.     Print IndexFormat$("MyInteger% = 0{?4:O8}", Str$(32767), "~")
  465.     Print IndexFormat$("MyInteger% = 0{?4:B16}", Str$(32767), "~")
  466.     Print "-------------------------------------------------------------------------------"
  467.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  468. End Sub ' IndexFormatTest2
  469.  
  470. ' /////////////////////////////////////////////////////////////////////////////
  471. ' Re: converting a number to a string, formatted like with "print using"
  472.  
  473. ' RhoSigma
  474. ' « Reply #3 on: March 05, 2022, 04:49:33 pm »
  475. ' « Last Edit: March 05, 2022, 04:55:02 pm »
  476.  
  477. ' Ah, so you talk about function overloading. Not possible in QB64 as is,
  478. ' but look on IndexFormat$, it's a function which needs to handle several
  479. ' different arguments/types too, it takes all the different parameters in
  480. ' the argument string, all added together, strings as is, numbers via STR$().
  481. ' Then, inside the functions you need to parse that whole argument string
  482. ' to get what you need.
  483.  
  484. ' Another way would be a user defined type.
  485.  
  486. ' As you can see, there are multiple ways to build universal functions,
  487. ' but unfortunately no such easy thing like a 'variants" type.
  488. ' Somewhere you have to go in and do your own coding.
  489.  
  490. ' Guess [member=9]SMcNeill[/member] could also show you a variant doing this with _MEM variables.
  491. ' He made a universal QuickSort function somewhere here in the forum,
  492. ' using _MEM variables to determine the array type which is to be sorted
  493. ' in his function.
  494.  
  495. ' EDIT:
  496. ' here's the _MEM sort, maybe you can derive something useful for your needs...
  497. ' https://qb64forum.alephc.xyz/index.php?topic=1601.0
  498.  
  499. 'Type aNumber
  500. '    typ AS STRING * 3
  501. '    n8 AS _BYTE
  502. '    n16 AS INTEGER
  503. '    n32 AS LONG
  504. '    n64 AS _INTEGER64
  505. '    ns AS SINGLE
  506. '    nd AS DOUBLE
  507. '    nf AS _FLOAT
  508. 'END TYPE
  509.  
  510. Function DoSomthingWithNumber$ (x As aNumber)
  511.     Select Case _Trim$(x.typ)
  512.         Case "n8"
  513.             'do _BYTE stuff here
  514.             DoSomthingWithNumber$ = "type _BYTE"
  515.         Case "n16"
  516.             'do INTEGER stuff here
  517.             DoSomthingWithNumber$ = "type INTEGER"
  518.         Case "n32"
  519.             'do LONG stuff here
  520.             DoSomthingWithNumber$ = "type LONG"
  521.         Case "n64"
  522.             'do _INTEGER64 stuff here
  523.             DoSomthingWithNumber$ = "type _INTEGER64"
  524.         Case "ns"
  525.             'do SINGLE stuff here
  526.             DoSomthingWithNumber$ = "type SINGLE"
  527.         Case "nd"
  528.             'do DOUBLE stuff here
  529.             DoSomthingWithNumber$ = "type DOUBLE"
  530.         Case "nf"
  531.             'do _FLOAT stuff here
  532.             DoSomthingWithNumber$ = "type _FLOAT"
  533.         Case Else
  534.             'unsupported type
  535.             DoSomthingWithNumber$ = "type unknown"
  536.     End Select
  537. End Function ' DoSomthingWithNumber$
  538.  
  539. Sub DoSomthingWithNumber_Test
  540.     Dim num As aNumber
  541.     Dim res As String
  542.  
  543.     Print "-------------------------------------------------------------------------------"
  544.     Print "Function overloading example by RhoSigma:"
  545.     num.typ = "n16"
  546.     num.n16 = 32767
  547.     res = DoSomthingWithNumber$(num)
  548.     Print res
  549.     Print "-------------------------------------------------------------------------------"
  550.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  551.  
  552. End Sub ' DoSomthingWithNumber_Test
  553.  
  554. ' /////////////////////////////////////////////////////////////////////////////
  555. ' bplus
  556. ' « Reply #5 on: March 05, 2022, 08:00:10 pm »
  557. ' Seems like Double parameter can handle various Types:
  558.  
  559. Function commaD$ (n#, nDecPlaces%) 'only works right for double# type
  560.     Dim place As Long, s$, front$, back$, func$
  561.     func$ = _Trim$(Str$(n#))
  562.     If Left$(func$, 1) = "-" Then s$ = "-": func$ = Mid$(func$, 2) Else s$ = ""
  563.     place = InStr(func$, ".")
  564.     If place = 0 Then place = Len(func$) + 1
  565.     While place > 4
  566.         func$ = Mid$(func$, 1, place - 4) + "," + Mid$(func$, place - 3)
  567.         place = InStr(func$, ",")
  568.     Wend
  569.     'fix to nDecPlaces
  570.     place = InStr(func$, ".")
  571.     If nDecPlaces% Then
  572.         If place Then
  573.             front$ = Mid$(func$, 1, place)
  574.             back$ = Mid$(func$, place + 1)
  575.             If Len(back$) > nDecPlaces% Then func$ = front$ + Left$(back$, nDecPlaces%)
  576.             If Len(back$) < nDecPlaces% Then func$ = front$ + Left$(back$ + String$(nDecPlaces%, "0"), nDecPlaces%)
  577.         Else
  578.             func$ = func$ + "." + String$(nDecPlaces%, "0")
  579.         End If
  580.     Else
  581.         If place Then func$ = Mid$(func$, 1, place - 1)
  582.     End If
  583.     commaD$ = s$ + func$
  584.  
  585. Sub commaD_Test
  586.     Dim i%
  587.     Dim j&
  588.     Dim k##
  589.  
  590.     Print "-------------------------------------------------------------------------------"
  591.     Print "commaD$ by bplus:"
  592.  
  593.     i% = 100000 * Rnd - 50000
  594.     Print "i%=" + _Trim$(Str$(i%))
  595.     Print "commaD$(i%, 2) returns " + Chr$(34) + commaD$(i%, 2) + Chr$(34)
  596.  
  597.     j& = 10000000 * Rnd - 5000000
  598.     Print "j&=" + _Trim$(Str$(j&))
  599.     Print "commaD$(j&, 2) returns " + Chr$(34) + commaD$(j&, 2) + Chr$(34)
  600.  
  601.     k## = 100000 * Rnd - 50000
  602.     Print "k##=" + _Trim$(Str$(k##))
  603.     Print "commaD$(k##, 4) returns " + Chr$(34) + commaD$(k##, 4) + Chr$(34)
  604.     Print "-------------------------------------------------------------------------------"
  605.  
  606.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  607. End Sub ' commaD_Test
  608.  
  609. ' /////////////////////////////////////////////////////////////////////////////
  610. ' SMcNeill
  611. ' « Reply #6 on: March 05, 2022, 10:26:57 pm »
  612. ' Try something like this:
  613. '     Print "FOO: "; format$("###.###", "123.456789")
  614. '     Print format$("###,.##", "123456789.987654321")
  615. ' Pass it the same format string you'd use with PRINT USING, and then
  616. ' the STR$ value of your number.  It'll return a string formatted just as
  617. ' PRINT USING would do.
  618.  
  619. ' bplus
  620. ' « Reply #7 on: March 06, 2022, 11:52:41 am »
  621. ' Oh! that looks like it gets around the Type problem.
  622. '     n = _NewImage(80, 80, 0)
  623. ' 0 the one mode you can read characters from, a point for Pete ;-))
  624.  
  625. ' Juanjogomez
  626. ' « Reply #8 on: March 14, 2022, 08:52:16 am »
  627. ' Re: converting a number to a string, formatted like with "print using"
  628. ' Very original, simple and effective
  629.  
  630. Function format$ (template As String, text As String)
  631.     d = _Dest: s = _Source
  632.     n = _NewImage(80, 80, 0)
  633.     _Dest n: _Source n
  634.     Print Using template; Val(text)
  635.     For i = 1 To 79
  636.         t$ = t$ + Chr$(Screen(1, i))
  637.     Next
  638.     If Left$(t$, 1) = "%" Then t$ = Mid$(t$, 2)
  639.     format$ = _Trim$(t$)
  640.     _Dest d: _Source s
  641.     _FreeImage n
  642. End Function ' format$
  643.  
  644. Sub FormatStringTest
  645.     Dim MySingle As Single
  646.     Dim MyDouble As Double
  647.     Dim MyString As String
  648.  
  649.     Print "-------------------------------------------------------------------------------"
  650.     Print "format$ by SMcNeill:"
  651.     Print
  652.  
  653.     MySingle = 123.456789
  654.     Print "MySingle=" + _Trim$(Str$(MySingle))
  655.     MyString = format$("###.###", _Trim$(Str$(MySingle)))
  656.     Print "format$(" + Chr$(34) + "###.###" + Chr$(34) + ", _Trim$(Str$(MySingle))) returns " + Chr$(34) + MyString + Chr$(34)
  657.     Print
  658.  
  659.     MyDouble = 123456789.987654321
  660.     Print "MyDouble=" + _Trim$(Str$(MyDouble))
  661.     MyString = format$("###,.##", _Trim$(Str$(MyDouble)))
  662.     Print "format$(" + Chr$(34) + "###,.##" + Chr$(34) + ", _Trim$(Str$(MyDouble))) returns " + Chr$(34) + MyString + Chr$(34)
  663.  
  664.     Print "-------------------------------------------------------------------------------"
  665.     Print "PRESS ANY KEY TO CONTINUE": Sleep: _KeyClear
  666.  
  667. End Sub ' FormatStringTest
  668.  

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
Re: converting a number to a string, formatted like with "print using"
« Reply #11 on: March 18, 2022, 11:43:51 am »
Quote from bplus: "0 the one mode you can read characters from, a point for Pete ;-))"

Yep, SCREEN 0 rules! Back in good old QBasic days, I used to place data on the screen in color 0, 0, at the end of one program, and then used RUN to start a new, related program. The new program would read the data from the screen, clear the screen, and use the data to determine the actions of the program. I never used CHAIN. I think it might be racist! :D

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: converting a number to a string, formatted like with "print using"
« Reply #12 on: March 18, 2022, 11:58:21 am »
Quote from bplus: "0 the one mode you can read characters from, a point for Pete ;-))"

Yep, SCREEN 0 rules! Back in good old QBasic days, I used to place data on the screen in color 0, 0, at the end of one program, and then used RUN to start a new, related program. The new program would read the data from the screen, clear the screen, and use the data to determine the actions of the program. I never used CHAIN. I think it might be racist! :D

Pete

Wow that is pretty cool idea for old QB stuff!

@madscijr I think my commaD$ does fail somewhere if you don't use double for sure (not even sure how far with doubles you can go). And if you just need to overcome Types use Steve's suggested approach, looks quite promising though I haven't tested limits. But if you want a great all purpose Format$ that does even more than QB original go with Rho Sigma's; it carries extra LOC and a little learning curve but what great versatility!
« Last Edit: March 18, 2022, 12:06:14 pm by bplus »

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #13 on: March 18, 2022, 12:18:34 pm »
@madscijr I think my commaD$ does fail somewhere if you don't use double for sure (not even sure how far with doubles you can go). And if you just need to overcome Types use Steve's suggested approach, looks quite promising though I haven't tested limits. But if you want a great all purpose Format$ that does even more than QB original go with Rho Sigma's; it carries extra LOC and a little learning curve but what great versatility!

Sounds good - I have them in my toolbox now!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
Re: converting a number to a string, formatted like with "print using"
« Reply #14 on: March 18, 2022, 12:20:03 pm »
Back in good old QBasic days, I used to place data on the screen in color 0, 0, at the end of one program, and then used RUN to start a new, related program. The new program would read the data from the screen, clear the screen, and use the data to determine the actions of the program.

That's a neat little hack there!
"Pretty sneaky, sis!" lol