Convert INI to CSV

Started by stanl, June 28, 2020, 04:51:43 AM

Previous topic - Next topic

stanl

The script below uses Regex and FileRead [possibly easier with WB's INI functions]. At first I considered converting to a hash but settled on formatting the ini as csv with 3 columns  Section,Key,Value.  The csv can then be easily converted to JSON, a fabricated Recordset, xml... I attached a sample .ini if anyone is interested in testing or optimizing.
Code (WINBATCH) Select


;Parse .ini file to .csv
gosub udfs
IntControl(73,1,0,0,0)
types="Ini Files|*.ini|"
cINI = AskFilename("Select Ini File To Convert", "C:\temp", types, "", 101)
If ! FileExist(cINI) Then Terminate(@TRUE,"Terminating",cINI:" Not Found")
cCSV = StrReplace(cINI,".ini",".csv")


cText = "Section,Key,Value":@CRLF
sect = "^\[(.+)\]$"
key = "(.+)=(.+)"
ObjectClrOption("useany","System")
oReg = ObjectClrNew('System.Text.RegularExpressions.Regex',sect)
oReg.CacheSize = ObjectType("ui2",30)
oReg1 = ObjectClrNew('System.Text.RegularExpressions.Regex',key)
oReg1.CacheSize = ObjectType("ui2",30)




h = FileOpen(cINI,"Read")
While 1
   x=FileRead(h)
   If x=="*EOF*" Then Break
   If StrLen(Strtrim(x))<1 Then Continue
   If oReg.IsMatch(x)
      cSect = StrClean(x,"[","",@FALSE,1)
      cSect = StrClean(cSect,"]","",@FALSE,1)
      retval=getkeys()
      If retval==0 Then Break
   Endif
Endwhile
h=FileClose(h)
oReg=0
oReg1=0


Message("Converted",cText)
;FilePut(cCSV,cText)


Exit


:WBERRORHANDLER
geterror()
Message("Error Encountered",errmsg)
Exit




:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine


#DefineSubRoutine getkeys()
ret=1
While 1
   x=FileRead(h)
   If x=="*EOF*"
      ret=0
      Break
   Endif
   If StrLen(Strtrim(x))<1 Then Break
   If oReg1.IsMatch(x)
      cKey = ItemExtract(1,x,"=")
      cValue = StrTrim(ItemExtract(2,x,"="))
      cText = cText:cSect:",":cKey:",":cValue:@CRLF
   Endif
Endwhile


Return(ret)


#EndSubRoutine


Return



td

Out of an abundance of curiosity and little if any common sense, I decided to try to create a CSV file using the WIL Ini* functions.  It got a bit conviluted...

Code (winbatch) Select
strInFile = DirScript():'lo.ini'
lSections = IniItemizePvt('', strInFile)
nSections = ItemCount(lSections, @Tab)
nRow = 0
aIo = ArrDimension(1,3)
for i=1 to nSections
   strSection = ItemExtract(i, lSections, @tab)
   lKeys = IniItemizePvt( strSection, strInFile)
   nKeys = ItemCount(lKeys, @Tab)
   ArrayRedim(aIo, Arrinfo(aIo, 1)+nKeys, -1)   ;; One too many rows.
   for j=1 to nKeys
      aIo[nRow,0] = strSection
      aIo[nRow,1] = ItemExtract(j, lKeys, @tab)
      aIo[nRow,2] = IniReadPvt( aIo[nRow,0], aIo[nRow,1], '', strInFile)
      nRow +=1
    next
next

ArrayFilePutCsv('Io.csv', aIo)

;; Did it work?
Run('notepad.exe', 'Io.csv')
exit



As an alternative to redimensioning the array, the section keys could be pre-counted and the array allocated accordingly.  Not that it makes much difference.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Not that I thought what I presented was by any means optimal, but it is useful. I was assuming I would face concerns with .ini comments or other rubbish [new term I just learned]. Also, I have to get more up to speed with regex.  You win, but mine had headers and not the  "" which make ultimate conversion to JSON or reading as a variable [for my present task]


[EDIT] and I apologize... Using "" to surround .csv allows commas in the parsed value columns. I changed my delimiter to | so that if subsequent converted/saved file is re-opened column data can be successfully parsed and don't have to deal with "". Also, will be working with legacy .ini which are pretty much basically well-formed.

td

I didn't post the script with any intension of "winning" some competition.  As I said, I was just curious about what it would take to parse an ini file and convert it to a csv file using WIL Ini* functions.  It got a little more convoluted than I thought it would at the outset. Trying stuff sometimes provides insights into new enhancements to WinBatch and the WIL language.

Of course, the CSV file output is just one of several different results you can obtain use the WIL Ini* functions.  If I had more ambition, I would have dumped it directly into JSON format or something.  But why bother? You already know more about the readily available system tools to do that than about any other WinBatch user.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Quote from: td on June 28, 2020, 03:21:10 PM
I didn't post the script with any intension of "winning" some competition.


Probably should have written Kudos.  ;)  I started with WB's ini functions but got a little lost.

ChuckC

Out of curiosity, where did you get lost when working with IniItemizePvt() and IniReadPvt()?

Also, I'm surprised that this thread didn't wander into the realm of WIL Maps as an intermediate representation of the contents of an INI file.  Unless I'm missing something regarding acceptable key values for a map object, it would seem to be trivial to load any INI fie into a map and then use that form of data representation to perform a transformation of the data to JSON or CSV content for output.

stanl

Quote from: ChuckC on June 29, 2020, 06:07:55 AM
Out of curiosity, where did you get lost when working with IniItemizePvt() and IniReadPvt()?


The task I adopted was to convert the ini w/out WB ini functions as the resultant csv will be eventually used as input for PS scripts. PS can do a similar converson but it is verbose at best.


In the past, I have used ini files with WB to often perform iterative %[execute this code]% commands so a majority of my translations would look fairly odd.


As for hashtable. I think I referred to those as well as using ini in my posts. The reason I need 3 columns is more a PS thing:



$capp = ($ccsv.Where({[string]$_.Section -like "*currentdb*" -and [string]$_.key -like "*table*"})).Value


This is a bit crude on my part but to 'gitter done' I am substituting a PS csv lookup to replace previous WB INIPvt read().

The beauty of WB has and will continue to be [often] an expedient way to get something done with fairly loose associations. I don't have that 'slack' anymore.