This is one of my first useful scripts. I run it on a highlighted text selection within Notepad++, but I've provided a sample formula and commented out the Scintilla-specific references.
I'm a rank amateur: Am I using good idiom? Is my approach to a state machine sensible?
# input_text = editor.getSelText()
input_text = '=HLOOKUP(TablePeriods[[#Headers],[YearMonth]],TablePeriods[[#All],[YearMonth]],MATCH([@Date],INDIRECT("TablePeriods[[#All],["&[@Account]&"]]"),-1))'
# initialize the state table
EVENTS = 11
STATES = 7
state_table = [[[0,0] for x in range(EVENTS)] for x in range(STATES)]
# event list and corresponding state table
event_list = [ "\"", "&", "(", ")", ",", "\n\r\t ", "[", "]", "{", "}" ] # last event is anything that doesn't match one of the other actions
state_table[0] = [[1,0], [0,1], [5,0], [0,3], [0,4], [0,5], [2,0], [0,0], [6,0], [0,0], [0,0]] # normal state
state_table[1] = [[0,0], [1,0], [1,0], [1,0], [1,0], [1,0], [1,0], [1,0], [1,0], [1,0], [1,0]] # double-quote comment
state_table[2] = [[2,0], [2,0], [2,0], [2,0], [2,0], [2,0], [3,0], [0,0], [2,0], [2,0], [2,0]] # inside bracketed table reference
state_table[3] = [[3,0], [3,0], [3,0], [3,0], [3,0], [3,0], [4,0], [2,0], [3,0], [3,0], [3,0]] # inside double-bracketed table reference
state_table[4] = [[4,0], [4,0], [4,0], [4,0], [4,0], [4,0], [-1,0], [3,0], [4,0], [4,0], [4,0]] # inside triple-bracketed table reference (I don't think this exists)
state_table[5] = [[1,2], [0,2], [5,2], [0,0], [0,2], [0,5], [2,2], [0,2], [0,2], [0,2], [0,2]] # found left-paren; only wrap and insert if not empty, like =row()
state_table[6] = [[6,0], [6,0], [6,0], [6,0], [6,0], [6,0], [6,0], [6,0], [6,0], [0,0], [6,0]] # inside curly-braced array
# initialize the state, parenthesis depth, and output text
current_state = 0
paren_depth = 0
output_text = ""
# define the tab and new line characters
TAB_CHAR = "\t"
NEW_LINE = "\r\n"
for z in input_text:
for a in range(len(event_list)):
if z in event_list[a]:
takeaction = state_table[current_state][a][1]
current_state = state_table[current_state][a][0]
break
else:
takeaction = state_table[current_state][-1][1] # this sets takeaction to the value when the test character does not match any event
current_state = state_table[current_state][-1][0] # this sets current_state to the value when the test character does not match any event
if current_state == -1:
current_state = 5 # -1 is an error and should be handled with some sort of error operation
if takeaction == 0: # just pass the characters along
output_text += z
elif takeaction == 1: # place character at same depth as only one on line
output_text += NEW_LINE + TAB_CHAR*paren_depth + z + NEW_LINE + TAB_CHAR*paren_depth
elif takeaction == 2: # previous character was a left paren and this one is not a right-paren
paren_depth = paren_depth + 1
output_text += NEW_LINE + TAB_CHAR*paren_depth + z
elif takeaction == 3: # character is a right paren not immediately following a left paren
paren_depth = paren_depth - 1
output_text += NEW_LINE + TAB_CHAR*paren_depth + z
elif takeaction == 4: # character is a comma, so start a new line at the paren depth
output_text += z + NEW_LINE + TAB_CHAR*paren_depth
elif takeaction == 5: # strip whitespace from the input outside of quotes
pass
else:
pass # should raise error, since the state table includes more actions than are defined
# editor.replaceSel(output_text)
print(output_text)
My code, without sample, is on Gisthub.