(PB) Loading CSV directly to a Hash Map

Posted by on February 21, 2013

When dealing with string maps, being able to easily load them from a file is a must. For example take language files for different local translations. The simplest, cleanest format would be CSV. The ideal data structure? — A hash map.

While trivial, this code will come in handy for many other things!

EnableExplicit
#CSV_QUOTE 	= "'"
#CSV_SEPARATOR 	= ","

Procedure IsEvenNumber(N)
   ProcedureReturn ( 1 - 1 & N )
EndProcedure
 
Procedure IsOddNumber(N)
   ProcedureReturn ( 1 & N )
EndProcedure 

Procedure.s RemoveQuotes( String.s )
	
	If Left(String, 1) = #CSV_QUOTE
		String = Mid( String, 2 )
	EndIf
	If Right(String, 1) = #CSV_QUOTE
		String = Left( String, Len(String) - 1 )
	EndIf
	
	ProcedureReturn String
EndProcedure

Procedure.i LoadStringMap( FileName.s, Map StringMap.s() )
	; escaping of quotes is currently not supported
	; if an uneven number of quotes is found on a line, the line is ignored.
	
	Define.i fp = ReadFile( #PB_Any, FileName )
	If IsFile(fp)
		
		While Not Eof(fp)
			
			Define.s line = Trim(ReadString( fp ))
			If line
				If CountString( line, #CSV_SEPARATOR ) => 1
					
					Define.i quote_count = CountString( line, #CSV_QUOTE )
					If IsEvenNumber( quote_count )
						
						Define.s key		= RemoveQuotes( StringField( line, 2, #CSV_QUOTE ) ) 
						Define.s content	= RemoveQuotes( StringField( line, 4, #CSV_QUOTE ) )
						
						StringMap( key ) 	= content
						
					EndIf
					
				EndIf
			EndIf
			
		Wend
		
		CloseFile(fp)
		ProcedureReturn MapSize( StringMap() )
	EndIf
	
EndProcedure

Example of data:

'Update', 'Actualizar'
'Databases', 'Bases de datos'
'Program', 'Programa'
'Options', 'Opciones'
'Export', 'Exportar'

Example of use:

NewMap spanish.s()
LoadStringMap( "locale/spanish.csv", spanish() )

ForEach spanish()
	
	Debug MapKey(spanish())
	Debug spanish()
	
Next

Couldn’t be easier!
Cheers.