Cecil
19+ years progress programming and still learning.
I had no practical reason to write this code only because I thought it would be fun to to. I saw a recent Google YouTube video
and I decided to quickly try it out in the ABL. Here is what I came up with. Copy and Paste the code into a procedure editor and run it.
Code:
/**
The Burrows–Wheeler transform (BWT, also called block-sorting compression) rearranges a character string into runs of similar characters.
This is useful for compression, since it tends to be easy to compress a string that has runs of repeated characters by techniques such
as move-to-front transform and run-length encoding. More importantly, the transformation is reversible, without needing to store any
additional data. The BWT is thus a "free" method of improving the efficiency of text compression algorithms, costing only some extra
computation.
**/
DEFINE TEMP-TABLE ttRotation
FIELD rowNumber AS INTEGER
FIELD rotation AS CHARACTER
INDEX idxRoration IS PRIMARY
rotation
INDEX idxRowNumber
rowNUmber.
/** function to transform a string using Burrows–Wheeler transform **/
FUNCTION TransformString RETURNS CHARACTER (INPUT chSourceString AS CHARACTER,
OUTPUT inIndex AS INTEGER).
DEFINE VARIABLE inLoop AS INTEGER NO-UNDO.
DEFINE VARIABLE inSortLoop AS INTEGER NO-UNDO.
DEFINE VARIABLE chPermString AS CHARACTER NO-UNDO.
DEFINE VARIABLE chLastColumn AS CHARACTER NO-UNDO.
EMPTY TEMP-TABLE ttRotation.
ASSIGN
chPermString = chSourceString.
/** Create a temp-table record for each permintation of the strings length with
the last character moved to the front of the string. **/
DO inLoop = 1 TO LENGTH(chSourceString):
CREATE ttRotation.
ASSIGN
ttRotation.rowNumber = inLoop
ttRotation.rotation = chPermString.
chPermString = SUBSTRING(chPermString, LENGTH(chPermString) ) + SUBSTRING(chPermString,1, LENGTH(chPermString) - 1).
END.
/** Re-sort the temp-table records into lex order and
re-assign the row number relative to the new order.**/
inSortLoop = 0.
FOR EACH ttRotation
BY ttRotation.rotation:
inSortLoop = inSortLoop + 1.
ttRotation.rowNumber = inSortLoop.
IF ttRotation.rotation EQ chSourceString THEN
ININDEX = ttRotation.rowNumber.
chLastColumn = chLastColumn + SUBSTRING(ttRotation.rotation, LENGTH(ttRotation.rotation) ).
END.
RETURN chLastColumn.
END FUNCTION.
/** Detransform the transformed string back into it's orignal value. **/
FUNCTION DETRANSFORMSTRING RETURNS CHARACTER (INPUT chLastColumn AS CHARACTER,
INPUT ININDEX AS INTEGER):
DEFINE VARIABLE inSortLoop AS INTEGER NO-UNDO.
DEFINE VARIABLE inInnerLoop AS INTEGER NO-UNDO.
DEFINE VARIABLE inLoop AS INTEGER NO-UNDO.
EMPTY TEMP-TABLE ttRotation.
/** Create a new table row array ready for detransformation. **/
DO inLoop = 1 TO LENGTH(chLastColumn):
CREATE ttRotation.
ASSIGN
ttRotation.rowNumber = inLoop.
END.
DO inLoop = 1 TO LENGTH(chLastColumn):
DO inInnerLoop = 1 TO LENGTH(chLastColumn):
FIND ttRotation
WHERE ttRotation.rowNumber EQ inInnerLoop
NO-ERROR.
ASSIGN
ttRotation.rotation = SUBSTRING(chLastColumn, inInnerLoop, 1) + ttRotation.rotation .
END.
inSortLoop = 0.
FOR EACH ttRotation
BY ttRotation.rotation:
inSortLoop = inSortLoop + 1.
ASSIGN
ttRotation.rowNumber = inSortLoop.
END.
END.
FIND ttRotation
WHERE ttRotation.rowNumber EQ ININDEX
NO-ERROR.
RETURN ttRotation.rotation.
END.
/** Main Code**/
DEFINE VARIABLE chSourceString AS CHARACTER NO-UNDO.
DEFINE VARIABLE chTransformedString AS CHARACTER NO-UNDO.
DEFINE VARIABLE inIndex AS INTEGER NO-UNDO.
MESSAGE
'ENTER YOUR NAME'
UPDATE
chYourName AS CHARACTER FORMAT "x(32)" AUTO-RETURN.
ASSIGN
chSourceString = SUBSTITUTE('&1 loves Progress OpenEdge', chYourName).
chTransformedString = TransformString(chSourceString, OUTPUT inIndex).
MESSAGE 'Source String:' SKIP QUOTER(chSourceString) SKIP(1)
'Transformed String:' SKIP QUOTER(chTransformedString) SKIP(1)
'De-transformed String:' SKIP QUOTER(DETRANSFORMSTRING(chTransformedString, inIndex ))
VIEW-AS ALERT-BOX INFO TITLE 'Burrows–Wheeler Transform Simple Demo'.