Open Forum > What's New
CSV Line Formatting Function
(1/1)
Support:
This Script BASIC function makes it easy to quickly format raw CSV (comma-separated values) files that has been a standard way of normalizing data for export / import. While searching for sample CSV data to play with I came across a site that posted the Sacramento crime log for January 1st, 2006 (24 hour period)
FYI: You can use either of the numeric formatting masks Script BASIC offers (BASIC or C style) and if you leave out the format info for a column, it will be ignored. This function will be added to the T.bas (Tools) extension module include file for the 2.2 release.
--- Code: Script BASIC ---' result = FormatLine(in_str, fmt_str, quo_char, num_spc) Note: num_spc = -1 uses TAB FUNCTION FormatLine(ln,fmtstr,qc,nsp) SPLITAQ ln BY "," QUOTE qc TO col SPLITA fmtstr BY "|" TO fmtcmd rs = "" FOR x = 0 to UBOUND(col) SPLITA fmtcmd[x] BY ":" TO fmt IF fmt[0] = "L" THEN tmp = LEFT(col[x] & STRING(fmt[1]," "),fmt[1]) GOSUB Margin ELSE IF fmt[0] = "R" THEN IF fmt[2] <> undef THEN tmp = FORMAT(fmt[2],col[x]) ELSE tmp = col[x] END IF tmp = RIGHT(STRING(fmt[1]," ") & tmp, fmt[1]) GOSUB Margin ELSE IF fmt[0] = "C" THEN pad = fmt[1] - LEN(col[x]) pboth = pad \ 2 prt = pad % 2 tmp = STRING(pboth," ") & col[x] & STRING(pboth," ") & STRING(prt," ") GOSUB Margin END IF NEXT GOTO Done Margin: IF nsp = -1 THEN tmp &= "\t" ELSE tmp &= STRING(nsp," ") END IF rs &= tmp RETURN Done: FormatLine = rsEND FUNCTION OPEN "SacramentocrimeJanuary2006.csv" FOR INPUT AS #1OPEN "sac.fmt" FOR OUTPUT AS #2fmtstr = "L:15|L:30|R:4|L:4|R:6|L:35|L:6|R:10:%~-##0.0000~|R:10:%~-##0.0000~"LINE INPUT #1, hdrWHILE NOT EOF(1) LINE INPUT #1, csvln csvln = CHOMP(csvln) PRINT #2, FormatLine(csvln,fmtstr,"",2),"\n"WEND CLOSE(1)CLOSE(2)
Output (7584 rows)
jrs@laptop:~/sb/sb22/test$ time scriba fmtline.sb
real 0m0.454s
user 0m0.415s
sys 0m0.036s
jrs@laptop:~/sb/sb22/test$
--- Code: ---1/1/06 0:00 3108 OCCIDENTAL DR 3 3C 1115 10851(A)VC TAKE VEH W/O OWNER 2404 38.5504 -121.3914
1/1/06 0:00 2082 EXPEDITION WAY 5 5A 1512 459 PC BURGLARY RESIDENCE 2204 38.4735 -121.4902
1/1/06 0:00 4 PALEN CT 2 2A 212 10851(A)VC TAKE VEH W/O OWNER 2404 38.6578 -121.4621
1/1/06 0:00 22 BECKFORD CT 6 6C 1443 476 PC PASS FICTICIOUS CHECK 2501 38.5068 -121.4270
1/1/06 0:00 3421 AUBURN BLVD 2 2A 508 459 PC BURGLARY-UNSPECIFIED 2299 38.6374 -121.3846
--- End code ---
Support:
I thought I would take this another step and create a CSV2SQL function for the T.bas (Tools) extension module include file. This is just my proof of concept attempt and I'll make a function call out of the following example for the 2.2 release.
I attached an example of the final CSV2SQL SUB running on Android Linux native.
--- Code: Script BASIC ---IMPORT sqlite.bas OPEN "SacramentocrimeJanuary2006.csv" FOR INPUT AS #1db = sqlite::open("sac116.db")fmtstr = "SSISISIRR"LINE INPUT #1, hdrhdr = CHOMP(hdr)SPLITA hdr BY "," TO colSPLITA fmtstr BY "" TO typlastcol = UBOUND(col)sql = "CREATE TABLE crime ("FOR x = 0 TO lastcol tmp = "" IF typ[x] = "S" THEN tstr = " TEXT" ELSE IF typ[x] = "I" THEN tstr = " INTEGER" ELSE IF typ[x] = "R" THEN tstr = " REAL" END IF tmp &= col[x] & tstr IF x <> lastcol THEN tmp &= ", " sql &= tmpNEXTsql &= ");"sqlite::execute(db, sql)sqlite::execute(db, "BEGIN TRANSACTION")WHILE NOT EOF(1) sql = "INSERT INTO crime VALUES (" LINE INPUT #1, csvln csvln = CHOMP(csvln) SPLITAQ csvln BY "," QUOTE "" TO col FOR x = 0 TO lastcol IF typ[x] = "S" THEN tmp = "'" & col[x] & "'" ELSE tmp = col[x] END IF IF x <> lastcol THEN tmp &= ", " sql &= tmp NEXT sql &= ");" sqlite::execute(db, sql)WENDsqlite::execute(db, "END TRANSACTION")sqlite::close(db)CLOSE(1)
Output
jrs@laptop:~/sb/sb22/test$ time scriba csv2sql.sb
real 0m0.763s
user 0m0.457s
sys 0m0.016s
jrs@laptop:~/sb/sb22/test$ sqlite3
SQLite version 3.8.2 2013-12-06 14:53:30
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .open sac116.db
sqlite> SELECT COUNT(*) FROM crime;
7584
sqlite> .q
jrs@laptop:~/sb/sb22/test$
Support:
I modified the fmtline() function to support either CSV or SQLite3 rows.
--- Code: Script BASIC ---' result = FormatLine(in_str/array, fmt_str, quo_char, num_spc) Note: num_spc = -1 uses TAB IMPORT sqlite.bas FUNCTION FormatLine(ln,fmtstr,qc,nsp) IF ISARRAY(ln) THEN col = ln ELSE SPLITAQ ln BY "," QUOTE qc TO col END IF SPLITA fmtstr BY "|" TO fmtcmd rs = "" FOR x = 0 to UBOUND(col) SPLITA fmtcmd[x] BY ":" TO fmt IF fmt[0] = "L" THEN tmp = LEFT(col[x] & STRING(fmt[1]," "),fmt[1]) GOSUB Margin ELSE IF fmt[0] = "R" THEN IF fmt[2] <> undef THEN tmp = FORMAT(fmt[2],col[x]) ELSE tmp = col[x] END IF tmp = RIGHT(STRING(fmt[1]," ") & tmp, fmt[1]) GOSUB Margin ELSE IF fmt[0] = "C" THEN pad = fmt[1] - LEN(col[x]) pboth = pad \ 2 prt = pad % 2 tmp = STRING(pboth," ") & col[x] & STRING(pboth," ") & STRING(prt," ") GOSUB Margin END IF NEXT GOTO Done Margin: IF nsp = -1 THEN tmp &= "\t" ELSE tmp &= STRING(nsp," ") END IF rs &= tmp RETURN Done: FormatLine = rsEND FUNCTION db = sqlite::open("sac16.db")stmt = sqlite::query(db,"SELECT * FROM crime LIMIT 1")sqlite::row(stmt)sqlite::FetchArray(stmt,columns)fmtstr = "L:15|L:30|R:4|L:4|R:6|L:35|L:6|R:10:%~-##0.0000~|R:10:%~-##0.0000~"PRINT FormatLine(columns,fmtstr,"",2),"\n"sqlite::close(db)
Output
--- Code: ---jrs@laptop:~/sb/sb22/test$ scriba fmtsqlrow.sb
1/1/06 0:00 3108 OCCIDENTAL DR 3 3C 1115 10851(A)VC TAKE VEH W/O OWNER 2404 38.5504 -121.3914
jrs@laptop:~/sb/sb22/test$
--- End code ---
Navigation
[0] Message Index
Go to full version