Thanks Claudio,
But we already have ways of transferring arrays from and to .ini files.
But there doesn't seem to be any way of taking in a text file with any level of complexity, even something relatively simple like this:
Code: Select all
{"First","First Item", ;
{{"First SubItem", "First SubItem from First", {||qout("First SubItem from First")}},;
{"Second SubItem", "Second SubItem from First", {||qout("Second SubItem from First")}},;
{"Third SubItem", "Third SubItem from First", {||qout("Third SubItem from First")}} } ;
}
I've tried stripping off the first beginning and last ending bracket, so that cText is a string ; and removing the line continuations ";" ; then removing the carriage returns and line feeds ; and then converting it with { &cText }. But it just leads to an error.
I might have to specify the array in some other form, but I really wanted for it to be identical to an array expression from .prg code.
Speaking of the .ini files, I updated Timm Sodtalbers' TEXT2DB last year, and will share it after cleaning up the code a little. So here's the part that pulls definitions from an .ini file into an array:
Code: Select all
FUNCTION Process_TextFile( Source_s, Destination_s, IniFile_s, AppendYN_s )
Local Field_s
Local Fields_a := {}
Local Nth_Expression_n := 0
Local Nth_Field_n := 1
Local lContinue := .T.
Local Lines_n := 0
Local Lines_s := ""
Local RDD_s := AllTrim( ProfileString( IniFile_s, "General", "RDD", "DBFCDX" ) )
Local Validation_Expression_s
Local Current_Line_n := 0
Local Nth_Line_n := 0
Local First_Line_s := ""
Local Expressions_to_Evaluate_a := {}
Local Expression_to_Evaluate_s := ""
Local Value_to_Add_to_Table_x := ""
Local PreParse_s := ""
Local PostProcess_s := ""
Local IsHeaderRow_s := ""
Local IsFooterRow_s:= ""
Local LineProcessDescription_s := ""
Local IsExpressionValid_b := .F.
Local Error_o
Local Error_b
Local SaveError_b
AppendYN_s = Upper( AppendYN_s )
PreParse_s := AllTrim( ProfileString( IniFile_s, "PreProcess", "PROC", "" ) )
Validation_Expression_s := ProfileString( IniFile_s, "Conditions", "Valid", "" )
IsHeaderRow_s := AllTrim( ProfileString( IniFile_s, "Headers_and_Footers", "header", "" ) )
IsFooterRow_s := AllTrim( ProfileString( IniFile_s, "Headers_and_Footers", "footer", "" ) )
// Loop through the list of fields.
DO WHILE lContinue = .T.
Field_s := ProfileString( IniFile_s, "Fields", AllTrim(STR(Nth_Field_n,4)), "" )
IF .NOT. EMPTY( Field_s )
AADD( Fields_a, { AllTrim( StrToken( Field_s, 1, "|" ) ), ;
AllTrim( StrToken( Field_s, 2, "|" ) ), ;
VAL( AllTrim( StrToken( Field_s, 3, "|" ) ) ), ;
VAL( AllTrim( StrToken( Field_s, 4, "|" ) ) ) } )
AADD( Expressions_to_Evaluate_a, StrToken( Field_s, 5, "|" ) )
Nth_Field_n := Nth_Field_n + 1
ELSE
lContinue := .F.
EndIf
ENDDO
IF LEN( Fields_a ) = 0
? "No fields defined in " + AllTrim( IniFile_s )
RETURN(.F.)
ELSE
If AppendYN_s == "YES"
If .NOT. File( Destination_s )
DBCREATE( Destination_s, Fields_a, RDD_s )
Else
// TODO: Check field specs against existing table.
EndIf
Else // If the table should be replaced
DBCREATE( Destination_s, Fields_a, RDD_s )
EndIf
EndIf
The .ini file looks something like this, for a fixed-width file:
[General]
DateFormat=mm.dd.yyyy
[Conditions]
#Ignore Header and Footer. Only Detail Records
#This is for a Fix-Width file
Valid=LEFT( LINETEXT, 4 ) <> 'HDR' .AND. LEFT( LINETEXT, 4 ) <> 'FTR'
[Fields]
1=FIRSTFLD |C| 5| 0| SUBSTR( LINETEXT, 1, 5 )
2=SECONDFLD |C| 50| 0| SUBSTR( LINETEXT, 6, 50 )
3=THIRDFLD |C| 65| 0| SUBSTR( LINETEXT, 157, 65 )
4=THISDATE |D| 8| 0| STOD( SUBSTR( LINETEXT, 307, 8 ) )
For a tab-delimited file, it might be something like this:
[General]
DateFormat=mm/dd/yyyy
[Conditions]
[PreProcess]
#Tab Delimited
PROC=HB_ATOKENS( LINETEXT, Chr(9) )
#If header=YES, then Skip the Header line, line #1
#If footer=YES, then Skip the Last line
[Headers_and_Footers]
header=YES
footer=NO
#This defines how to extract each field from each line in the text file.
#Some functions that can be used, include
# Remove_Beg_End_Quotes( value ) - Remove quotes from the beginning and ending of strings
# SubString( value, StartingPosition, EndingPosition ) - Standard Substring function
# CTOD( value ) - Convert Date string "mm/dd/yyyy" to a Date
# STOD( value ) - Convert Date string "yyyymmdd" to a Date
# Val( value) - Convert a string value to a number
[Fields]
1=FIRSTFLD |C| 50| 0| Remove_Beg_End_Quotes( TOKENS_A[1] )
2=SECONDFLD |C| 15| 0| Remove_Beg_End_Quotes( TOKENS_A[2] )
3=THIRDFLD |C| 8| 0| TOKENS_A[3]
4=THISDATE |D| 8| 0| CTOD( TOKENS_A[4] )
I'll try to share this with the forum soon, as well as a version that parses and exports directly to a spreadsheet, or filters out lines to output a shortened fixed-width or delimited file.