I'm trying to indent a pseudo-code that I have column A and is not indented. Basically I'm trying to add 4 spaces when is time to do it even is there is a nested if/elseif/else/end block or while/end block
This is my input:
WHILE TRUE
DISPLAY "Welcome to Bank ATM - Cash Withdrawal"
amount = INPUT "How much would you like to withdraw today?"
IF (amount MOD 10) != 0 THEN
DISPLAY "You can only withdraw a multiple of ten!"
ELSE
IF amount<10 THEN
DISPLAY "You can withdraw only above of £10"
ELSEIF amount>1000 THEN
DISPLAY "You can only withdraw between £10 and £1000"
ELSE
notes20 = amount DIV 20
notes10 = (amount MOD 20) / 10
DISPLAY "Collect your money: "
DISPLAY " >> £20 Banknotes: " + notes20
DISPLAY " >> £10 Banknotes: " + notes10
DISPLAY "Thank you for using this Python Bank ATM."
DISPLAY "Good Bye."
END
END
END
And this is my current attempt that currently is printing exactly the same as input.
Sub indent()
a = WorksheetFunction.Transpose(Range("A1:A21"))
if_count = 0
end_count = 0
For i = 1 To UBound(a)
If a(i) = "IF" Then
If (if_count = 0 And end_count = 0) Then
Debug.Print a(i)
if_count = if_count + 1
ElseIf if_count > 0 Then
Debug.Print " " & a(i)
if_count = 0
Else
Debug.Print a(i)
End If
Else
Debug.Print a(i)
End If
Next
End Sub
The output I'm looking for is like this:
WHILE TRUE
DISPLAY "Welcome to Python Bank ATM - Cash Withdrawal"
amount = INPUT "How much would you like to withdraw today?"
IF (amount MOD 10) != 0 THEN
DISPLAY "You can only withdraw a multiple of ten!"
ELSE
IF amount<10 THEN
DISPLAY "You can withdraw only above of £10"
ELSEIF amount>1000 THEN
DISPLAY "You can only withdraw between £10 and £1000"
ELSE
notes20 = amount DIV 20
notes10 = (amount MOD 20) / 10
DISPLAY "Collect your money: "
DISPLAY " >> £20 Banknotes: " + notes20
DISPLAY " >> £10 Banknotes: " + notes10
DISPLAY "Thank you for using this Python Bank ATM."
DISPLAY "Good Bye."
END
END
END
In image would look like this:
Thanks for any help.
Just as addition to Taller's valid & clever solution, I want to demonstrate how to organize a dictionary storing the integrated logic separately; this is done via 4 pairs only of positive or negative level increments based on predefined code keywords like e.g. "IF", "ELSE", "END"... etc. Thus each dictionary call returns an increment (or decrement) to the current code hierarchy level.
The main routine Indent
consists of the following steps:
Functions
A certain challenge was to outsource B's padding routine per keyword as separate function Pad()
and to provide it with predefined level increments via dictionary Incr
- c.f. Pad section 1)
.
The relevant parts therein are:
incr
with level increments (Set incr = LoadIncr(prefix)
).lvl
.Prefilling the dictionary via helper Function LoadIncr()
associates predefined keywords like "IF", "WHILE", "ELSE",.. etc. with a couple of fixed level increments changing the hierarchy level individually.
Main routine Indent
Option Explicit ' head of code module
'Site: https://stackoverflow.com/questions/78332116/how-to-add-BLANKs-to-pretty-print-pseudo-code/78332183#78332183
'Auth: https://stackoverflow.com/users/6460297/t-m
'Date: 2024-04-16
Sub Indent()
With Sheet1 ' << qualify worksheet reference according to your needs
Dim lastRow As Long: lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
'A) Assign Range content (pseudo code) to 2D datafield array
Dim code As Variant: code = .Range("A1:A" & lastRow).Value2
'B) Pad lines within the code array first
Dim i As Long
For i = 1 To UBound(code)
Dim keyword As String: keyword = UCase(Split(code(i, 1))(0))
' >> Apply padding upon code elements<<
code(i, 1) = pad(keyword) & code(i, 1) ' prepend padding to original code string
Next
'C) Write entire code array to target range (or VBE's Immediate Window) eventually
.Range("B1").Resize(UBound(code), 1).Value = code
Debug.Print Join(WorksheetFunction.Transpose(code), vbNewLine)
End With
End Sub
Function Pad()
Function pad(ByVal keyword As String, Optional cnt As Long = 4) As String
Const prefix As String = "$"
'1) Prefill dictionary with level increments
Dim incr As Dictionary
Set incr = LoadIncr(prefix)
'2) Adapt keyword with a given prefix
keyword = prefix & keyword ' add prefix for search
If Not incr.exists(keyword) Then keyword = prefix ' no predefined keyword
'3) Return correct keyword padding
Static lvl As Long ' remember indent level
lvl = lvl + incr(keyword)(0)
pad = String(lvl * cnt, " ") ' return padded line
lvl = lvl + incr(keyword)(1)
End Function
Helper function LoadIncr()
Function LoadIncr(Optional ByVal prefix As String = "$") As Dictionary
'Purp: Add predefined keys and increments to dictionary and return it as a whole
'1) Set Dictionary to memory
Dim myDict As Object ' late binding
Set myDict = CreateObject("Scripting.Dictionary")
'2) Add 4 predefined key types and couples of level increments (before|after padding)
Dim myKey As Variant
'a) Start keys
For Each myKey In Array("IF", "WHILE")
myDict.Add prefix & myKey, Array(0, 1)
Next
'b) Mid keys
For Each myKey In Array("ELSE", "ELSEIF")
myDict.Add prefix & myKey, Array(-1, 1)
Next
'c) End keys
For Each myKey In Array("END", "WEND")
myDict.Add prefix & myKey, Array(-1, 0)
Next
'd) All Others (i.e. in between above predefined keys)
myDict.Add prefix & "", Array(0, 0)
'3) Return Dictionary (including predefined level increments) as Function result
Set LoadIncr = myDict
End Function