Page 1 of 2 12>
Topic Options
#214090 - 2022-04-26 04:56 PM Issue with Array not ignoring empty lines
Robdutoit Offline
Hey THIS is FUN
***

Registered: 2012-03-27
Posts: 363
Loc: London, England
I have created a very simple udf to read an ini file and install the printers listed in that ini file. However, for some reason, the code is returning an extra return or item in the array. I have had to exclude empty lines to get rid of that extra result.

Here is the udf

 Code:
Function PrintInstall($Section)

	$Handle = Freefilehandle ()
	
	If $handle > 0
		If Open ($handle, $iniFile) = 0
			$PrintServer = ReadProfileString($iniFile, "PrintServer", "Printer")
			$printerKeys = split(ReadProfileString($iniFile, $Section, ""),chr(10))
			FOR each $printerKey in $printerKeys
				IF $printerKey <> ""
					$printer = ReadProfileString($iniFile, $Section, $printerKey)
			? "Install the $Printer"
				ENDIF
			NEXT
			
			IF Close($handle)
				Beep
				? "Error closing file!"
			ENDIF
		ELSE
			? "Unable to open" + $iniFile
		ENDIF
	ELSE
		? "Unable to obtain a free system handle."
	ENDIF
	
EndFunction


I have to put this line in - IF $printerKey <> "" - otherwise the code returns an extra entry. I think it is something to do with empty lines in the ini file.

This is the ini file sections that this coding is reading

 Quote:

[PrintServer]

Printer = ServerName

[Accounting Printers]

printer1 = Ricoh
printer2 = Sharp
printer3 = Brother
printer4 = Xerox


Top
#214091 - 2022-04-26 11:12 PM Re: Issue with Array not ignoring empty lines [Re: Robdutoit]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
This may not be the source of your issue....But I think you're getting some stuff mixed up with Open/ReadLine and ReadProfileString functions. You don't have to do the filehandle, and Open stuff to use ReadProfileString.
Top
#214092 - 2022-04-26 11:37 PM Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
I am having a horrendous time trying to use ReadProfileString properly. I got your code down to the simplest form, and it's still giving me weird stuff back.

Can someone tell me why this code....
 Code:
$printers = Split(ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", ""), chr(10))

For Each $printerKey in $printers
	? "Install the " + ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", $printerKey)
Next

get $

Would give back this???
 Quote:
Install the Ricoh
Install the Sharp
Install the Brother
Install the Xerox
Install the printer1
printer2
printer3
printer4

For some reason it keeps on spitting out the key names at the end.

This is the INI files I'm using.
 Quote:
[PrintServer]
Printer = ServerName

[Accounting Printers]
printer1 = Ricoh
printer2 = Sharp
printer3 = Brother
printer4 = Xerox

Top
#214093 - 2022-04-27 01:00 AM Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
I can confirm that I have seen this problem many times, and never once thought to post about it. I too have a line in my scripts that checks for a blank data to avoid the issue.

 Code:
$printers = Split(ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", ""), chr(10))

For Each $printerKey in $printers
    if $printerkey<>""
	  ? "Install the " + ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", $printerKey)
	 endif
Next

get $


I think it might be a bug.

Top
#214094 - 2022-04-27 01:06 AM Re: Issue with Array not ignoring empty lines [Re: Allen]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
 Code:
$printers = Split(ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", ""), chr(10))
? ubound($printers)


Returns 4 instead of 3 using the provided test.ini.

The 4th result is what is causing the odd output...

Top
#214095 - 2022-04-27 01:41 AM Re: Issue with Array not ignoring empty lines [Re: Allen]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
If it is a bug... we have been dealing with it quietly for a long time. Glenn posted enumini in 2004, and his work around was

 Code:
if len($arrayitem) > 0


EnumINI
http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=135385

Top
#214096 - 2022-04-27 03:07 PM Re: Issue with Array not ignoring empty lines [Re: Allen]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Found an example in an old forum post, where someone used Left($string, -1) to trim a space off the end, and it works (Trim() also seems to work). Seems that the readprofilesstring adds an extra line feed at the end, which causes the split to add the extra array item. Why it fills that blank item with the keys names, I can't say. Odd that I've used INI's so much in the past and don't recall ever running into this issue at all. Could just be an age issue, lol.

 Code:
$printers = Split(Left(ReadProfileString(@ScriptDir + "\test.ini", "AccountingPrinters", ""),-1), chr(10))

For Each $printerKey in $printers
	? "Install the " + ReadProfileString(@ScriptDir + "\test.ini", "AccountingPrinters", $printerKey)
Next

get $

Top
#214097 - 2022-04-27 03:17 PM Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Back to the original post...Below is how I would handle the PrintInstall function. This seems to return the correct count of printer, regardless of blank lines in the INI file.

 Code:
$iniFile = @ScriptDir+"\test.ini"
$Section = "Accounting Printers"

PrintInstall($iniFile, $Section)

Function PrintInstall($iniFile, $Section)
	$PrintServer = ReadProfileString($iniFile, "PrintServer", "Printer")
	$printerKeys = Split(Left(ReadProfileString($iniFile, $Section, ""), -1),chr(10))
	FOR each $printerKey in $printerKeys
		$printer = ReadProfileString($iniFile, $Section, $printerKey)
		? "Install the $Printer"
	NEXT
EndFunction

Top
#214098 - 2022-04-27 03:28 PM Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
mole Offline
Getting the hang of it

Registered: 2003-01-01
Posts: 77
Loc: Indian Head, Maryland, USA
 Originally Posted By: ShaneEP
Could just be an age issue, lol.



My thought as well, as in my case, OLD age. I used to use INI's too and recall stumbling over this issue a few times. Getting trim() in the proper location seemed to solve the issue if my memory is working. Never crossed my mind it could be a bug, but chalked up to being a chemist and not a programmer!
_________________________
mole

Who is John Galt?

Top
#214099 - 2022-04-28 11:42 AM Re: Issue with Array not ignoring empty lines [Re: mole]
Robdutoit Offline
Hey THIS is FUN
***

Registered: 2012-03-27
Posts: 363
Loc: London, England
Never occurred to me that it could be a bug. I will try the trim and left options and see what happens. But the trim/left options would essentially be the same thing as the way that I have done it. A workaround to fix a bug in the readprofilestring command. I just assumed that I was doing something wrong in the coding.

What I will do first is get my code working without the handle, file open first to reduce unnecessary code. I just assumed that I needed it because I have always used handles when opening text files. Not sure why readprofilestring doesn't seem to need it as it's still opening a file which could be locked for some reason.

Top
#214100 - 2022-04-28 12:22 PM Re: Issue with Array not ignoring empty lines [Re: mole]
Robdutoit Offline
Hey THIS is FUN
***

Registered: 2012-03-27
Posts: 363
Loc: London, England
I have removed all the handles, open, close commands and the script still works. So thank you for that. It makes it a lot easier to read the code without all those open/close handles.

I have tried the Left option and I prefer that to the way that I or Glenn did it as it removes an unnecessary if,endif statement. I have just made a note to use the Left option when using readprofilestrings to get round that bug.


Edited by Robdutoit (2022-04-28 04:50 PM)

Top
#214101 - 2022-04-28 02:22 PM (NA) Re: Issue with Array not ignoring empty lines [Re: Robdutoit]
Ruud van Velsen Moderator Offline
Developer
*****

Registered: 1999-05-06
Posts: 391
Loc: Amsterdam, The Netherlands
Thanks for reporting - this is a side-effect of ReadProfileString adding a (superfluous) carriage-return after the last entry in a section. Basically, this is what it returns:

Ricoh(carriage-return)
Sharp(carriage-return)
Brother(carriage-return)
Xerox(carriage-return)

If you'd like this changed: let me know.


Edited by Ruud van Velsen (2022-04-28 02:26 PM)

Top
#214103 - 2022-04-28 03:51 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: Ruud van Velsen]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Rob...I debated on which way to go...Using the Left(string, -1) route, vs the Trim() route, and would recommend sticking with just the Left() method. In my mind, this altered the return values the least, and would avoid any potential issues if there were ever intentional spaces at the beginning or ending of values. That's just my 2 cents, even though Trim() may seem simpler.

Ruud, thanks for the feedback. In my opinion it seems odd to get the extra carriage return, but I can also understand why it was programmed that way. At this point it might be best to leave it as is, as it may break a lot of existing code that currently works around it. Some improved documentation on that function may be the better solution, but I'll let others chime in. I am curious however as to how all the section key names found their way into that last empty array item in my example above. I would have expected it to be blank.

 Quote:
Install the Ricoh
Install the Sharp
Install the Brother
Install the Xerox
Install the printer1
printer2
printer3
printer4

Top
#214104 - 2022-04-28 04:49 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
Robdutoit Offline
Hey THIS is FUN
***

Registered: 2012-03-27
Posts: 363
Loc: London, England
Shane - Sorry my post should have read Left, not Left Trim. I am using the Left option as it worked perfectly and got rid of the extra if,endif statement. So I didn't try the trim method. I will edit that post shortly.

Rudd - I would suggest changing the code for readprofilestring to remove the extra carriage return as technically it is a bug and it would seem that over the years many people have had to develop a workaround for it. I would expect anyone wanting to upgrade to the latest version of Kixtart to read the Release Notes to see what has changed before updating to the latest Kixtart variable. So I wouldn't expect it to break code as people should be reading the release notes before updating.

I don't know if you noticed, but I also created two more posts (in addition to the @Producttype bug which is being fixed in kix 4.69). That was for @domain variable and the syntax differences between AddPrinterConnection and DelPrinterConnection just in case you want to review whether it is worth making any changes there. Thanks.

The posts in question are:

http://kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=214011#Post214011
http://kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=214008#Post214008

Top
#214105 - 2022-04-28 06:20 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
Ruud van Velsen Moderator Offline
Developer
*****

Registered: 1999-05-06
Posts: 391
Loc: Amsterdam, The Netherlands
Hi Shane, considering the last entry in the array is empty, the last ReadProfileString call basically comes down to this:

ReadProfileString(@ScriptDir + "\test.ini", "Accounting Printers", "")

Which tells it to return all keynames in that section.

Top
#214108 - 2022-04-28 07:33 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: Ruud van Velsen]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Ahh, yea that makes sense. Thanks for the explanation.
Top
#214109 - 2022-04-28 11:12 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: ShaneEP]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
If you think about this, it isn't a bug. If you enumerate the sections or keys, each object returned is terminated by a newline:
 Code:
V1\nV2\nV3\n
You are using LINE TERMINATORS as DELIMITERS and have 3 delimiters, thus you have FOUR fields.

To properly parse the values, you need to translate LINE TERMINATION to DELIMITERS by removing the last (excess) line terminator. That's precisely what EnumIni() does, along with some error handling.
 Code:
; Get an INI enumeration of keys
$Tmp = ReadProfileString(@ScriptDir + '\test.ini', 'Accounting Printers', '')
; If we got data, remove the last line terminator and split on the \n delimiters
If Trim($Tmp)
  $aData = Split(Left($Tmp, Len($Tmp) - 1), Chr(10))
EndIf
; Enumerate the array of section keys and get the values
For Each $Key In $aData
  'Key: ' $Key ?
  'Val: ' ReadProfileString(@ScriptDir + '\test.ini', 'Accounting Printers', $Key) ?
Next
Quit 0
This outputs exactly what you would expect:
 Code:
Key: printer1
Val: Ricoh
Key: printer2
Val: Sharp
Key: printer3
Val: Brother
Key: printer4
Val: Xerox


If you don't remove the last line terminator, you have an extra delimiter, the last field after that is empty, so you get an additional enumeration string.

Basic coding - understand your data structure before you use it!

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#214111 - 2022-04-29 12:50 AM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: Glenn Barnas]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
I agree it's not a bug with the further explanation, BUT... you have to admit getting a bunch of data, from seemingly nowhere, is jarring. We've all worked around it in our own ways, but the question is, do we need to continue to work around it? Ruud is offering us a "fix", and I think we should at least consider it. Is there any reason this "fix" would not be desirable? I haven't come up with a reason yet, but I'm open to hearing other's ideas on the subject.
Top
#214114 - 2022-04-29 11:06 AM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: Allen]
Robdutoit Offline
Hey THIS is FUN
***

Registered: 2012-03-27
Posts: 363
Loc: London, England
I don't fully understand the code that you wrote Glenn. But my take on the issue would be this.

Is the way that readprofilestring currently works returning the intended result? I would not focus on whether it's technically a bug, but what the expected result of the command should be.

Using Shane's example he is getting Printer1-Printers 4 after listing the actual printers, which is clearly not the intended result of the readprofilestring. It sounds to me that the issue is the way that readprofilestring determines what is on a line creating four fields instead of three. So the code is technically correct, but is not returning the intended result unless an extra bit of coding is added such as trim, left or not equal to 0 etc to remove the last line.

The process is not important, the outcome is.

Top
#214116 - 2022-04-29 05:57 PM Re: (NA) Re: Issue with Array not ignoring empty lines [Re: Robdutoit]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
Allen - it's not broken so a "fix" would potentially affect all code that properly processes the results and is not a good solution IMO. If anything, the documentation should be updated to clarify that this is not a DELIMITED string but a String LIST of newline-terminated values. The data isn't coming from "nowhere", it's specifically requested because of poor data handling. The documentation, in fact, doesn't reference the returned format at all.

Ruud - the line terminator is Newline (Chr(10)) and not Carriage Return (Chr(13) as you noted.

Rob - Yes, it is returning the intended result.

This is what's happening, and why you aren't processing the data correctly.

Here's a simple example to help it make sense:
If you had a delimited string "A,B,C", you see that it's delimited with commas. There are TWO delimiters that result in 3 fields. The Split() on this string returns a 3-element array. Change this to "A,B,C," and you have 3 delimiters and 4 fields (the last is blank). A split on this returns a 4-element array. This is what you're getting from your code.

The result of ReadProfileString($File, $Section, '') does NOT return a delimited string. It returns a string list - a set of lines terminated with a Newline:
Line1 {NL}
Line2 {NL}
Line3 {NL}

If you look at this as a string, you get this: "Line1 {NL}Line2 {NL}Line3 {NL}" - 3 delimiters so 4 fields. The problem is that this isn't intended to be a delimiter because it isn't just a string, it's a string that contains a set of lines. When you split this using Chr(10) (newline) as a DELIMITER, it includes the last LINE TERMINATOR character and adds an "unseen" empty field. You cannot interchange the use of delimiters and line terminators.

To properly use the output of the ReadProfileString enumeration, you MUST remove the last Line Terminator (because it isn't a delimiter!). THEN and only then can you use the Line Terminator character as a delimiter, because the string now looks like "Line1 {NL}Line2 {NL}Line3" - 2 Delimiters, thus 3 fields.

If you don't eliminate the last LINE TERMINATOR, you wind up with an empty value. Consider what's happening:
 Code:
; Get the keys defined in the section
$aKeys = Split(ReadProfileString($File, $Section, '')
; Enumerate the keys
; just display the result of ReadProfileString for each key - assume there are 3 keys
; but we don't strip the final Line Terminator, so we have 4 elements in the array.
ReadProfileString($File, $Section, $aKey[0]) ?         ; Displays data from "Line 1" key
ReadProfileString($File, $Section, $aKey[1]) ?         ; Displays data from "Line 2" key
ReadProfileString($File, $Section, $aKey[2]) ?         ; Displays data from "Line 3" key
; You have 4 elements, the last is blank
ReadProfileString($File, $Section, $aKey[3]) ?         
; Displays the enumeration of File,Section because $aKey[3] is null! so outputs:
; Line1
; Line2
; Line3
Basically, either trim the last character from the output of the enumeration or use a pre-built function like EnumIni.

The Trim() in my example is not required - it's simply there to create a Boolean result to proceed when any data is returned or skip if a null / empty string was returned. I could have also used an If Not @ERROR instead. The most important thing is first getting the String List, then (if not empty), use Left() and Len() to trim the last line termination character. That logic essentially converts a String List to a Delimited String that can be split into the correct number of fields.

Shane's code is correct because he's removing the final delimiter, albeit through a "golf" mechanism that would not be obvious or intuitive. The left(String, -#) can trim a string by implicitly referencing the length from the end, so his and my examples provide the same result. I would not allow his example in production as it is not a clear/documented method, but something that was "discovered" and leveraged to reduce coding character counts for our Kix-golf games. When his code displays the excess list, it's when he didn't trim the final line terminator.

Finally, Trim() has no bearing whatsoever on processing INI files. You can have blank lines and comments (; or #) to your hearts content in an INI file and there will be zero impact on reading, writing, or enumerating it.


_________________________
Actually I am a Rocket Scientist! \:D

Top
Page 1 of 2 12>


Moderator:  Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 370 anonymous users online.
Newest Members
Timothy, Jojo67, MaikSimon, kvn317, kixtarts2025
17874 Registered Users

Generated in 0.108 seconds in which 0.064 seconds were spent on a total of 14 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org