Page 1 of 2

How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 4:35 pm
by HGAutomator
Hi,

There are lots of functions that do this, already written. But the arrays aren't defined with an array syntax, inside the file.

Let's say you have a text file with

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")}} } ;
						}, ;
						{"Second","Second Item", ;
								{{"First SubItem",     "First SubItem from Second", {||qout("First SubItem from Second")}},;	
               	{"Second SubItem", "Second SubItem from Second",  {||qout("Second SubItem from Second")}},;
               	{"Third SubItem", "Third SubItem from Second",  {||qout("Third SubItem from Second")}}  } ;
						}, ;
						{"Third","Third SubItem",0}, ;
						{"Fourth","Fourth SubItem",{||qout("Fourth SubItem")} }  ;
	}
or an assignment like

Code: Select all

MainArray_a := { ;
						{"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")}} } ;
						}, ;
						{"Second","Second Item", ;
								{{"First SubItem",     "First SubItem from Second", {||qout("First SubItem from Second")}},;	
               	{"Second SubItem", "Second SubItem from Second",  {||qout("Second SubItem from Second")}},;
               	{"Third SubItem", "Third SubItem from Second",  {||qout("Third SubItem from Second")}}  } ;
						}, ;
						{"Third","Third SubItem",0}, ;
						{"Fourth","Fourth SubItem",{||qout("Fourth SubItem")} }  ;
	}
(where we have MainArray_a declared as PUBLIC inside the calling routine).

How can we read this array from a text .txt file, and populate it in an array variable inside the program?

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 5:44 pm
by AUGE_OHR
hi,

it "seem" like definition for a TREE ...
but as it is "one line" (?) i "see" no "Delimiter" ... hm

for TREE there was a Way with XML File ... is this what you search :?:

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 6:04 pm
by Anand
Hi HGAutomator

Attached code (very old from Clipper time), which I use still today to save and restore an array.
See SaveArray(), RestArray()

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 6:48 pm
by HGAutomator
Nope. I'd like to see if it's possible to import an array from a text file, where the array is defined the same way it would be in a .prg code file.
AUGE_OHR wrote: Sun Feb 06, 2022 5:44 pm hi,

it "seem" like definition for a TREE ...
but as it is "one line" (?) i "see" no "Delimiter" ... hm

for TREE there was a Way with XML File ... is this what you search :?:

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 7:13 pm
by HGAutomator
Thanks Anand, I'll play with it a bit. So far, RestArray returns an empty string from the file with the array.

I even tried pulling the file into a string, then macro expanding the string, but that generates an error.
Anand wrote: Sun Feb 06, 2022 6:04 pm Hi HGAutomator

Attached code (very old from Clipper time), which I use still today to save and restore an array.
See SaveArray(), RestArray()

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 8:14 pm
by Claudio Ricardo
Hi... Maybe this:
https://www.hmgforum.com/viewtopic.php? ... ini#p67214
I do for store array in .ini file... For save in .txt:
Set Alter To &cFName
Set Alter On
? ArrayToIni (aArray)
Set Alter To

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 9:32 pm
by HGAutomator
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.















Claudio Ricardo wrote: Sun Feb 06, 2022 8:14 pm Hi... Maybe this:
https://www.hmgforum.com/viewtopic.php? ... ini#p67214
I do for store array in .ini file... For save in .txt:
Set Alter To &cFName
Set Alter On
? ArrayToIni (aArray)
Set Alter To

Re: How to read a multi-dimensional array from a text file?

Posted: Sun Feb 06, 2022 10:57 pm
by AUGE_OHR
hi,

all is "one String" ( Codeblock), right :?:
but in that String ( Codeblock) there is "real" no ";" so you can not STRTRAN() or AT(";",cString)

---

neverless i guess you want some "Action" which is easy using qout()
but how with "real" Function and Parameter :?:

Re: How to read a multi-dimensional array from a text file?

Posted: Mon Feb 07, 2022 12:21 am
by HGAutomator
No. The string isn't a codeblock, but it contains some embedded codeblocks. Strtran wasn't a problem for the string, it did strip the semi-colons out, along with the carriage returns and line feeds. Also, the opening parent array bracket, and the closing one.

This is the first array in the original array, which of course we couldn't pull into the program. This is somewhat simpler, but we still can't import it into an array inside the app.

Maybe I'm misunderstanding what you're saying, Auge.

{"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")}} } ;
}

Re: How to read a multi-dimensional array from a text file?

Posted: Mon Feb 07, 2022 12:26 am
by Claudio Ricardo
Hi... Two options to convert your array (as is) to .txt file
Comment and discomment lines... (need add more for/next bucles)
Compiled with HMG 3.4.4 32 bits.