How do I parse a ctrl-A delimited string?

Short answer: “\001” vs data

Use the vs (vector from scalar) function:

q)”\001″ vs fstring

We can combine vs with /: (each right) to break up each component:

q)”=” vs/: “\001” vs fstring
“f1” “va”
“f2” “vb”
“f3” “vc”

Note that you cannot put any space between vs and /:. If you did, that would be a comment.

We might next turn fstring’s contents into a table using a combination of flip and ! (dict):

q)flip "=" vs/: "\001" vs fstring
"f1" "f2" "f3"
"va" "vb" "vc"
q)`field`value ! flip "=" vs/: "\001" vs fstring
field| "f1" "f2" "f3"
value| "va" "vb" "vc"
q)flip `field`value ! flip "=" vs/: "\001" vs fstring
field value
"f1"  "va"
"f2"  "vb"
"f3"  "vc"

This is almost what we want. Usually, though, you want the field names to be symbols rather than strings. We can do that by applying (@) the $ (cast) operator to (only) the values of the field column:

q)columns: @[flip "=" vs/: "\001" vs fstring; 0; `$]
f1   f2   f3
"va" "vb" "vc"
q)flip `field`value ! columns
field value
f1    "va"
f2    "vb"
f3    "vc"

However, there is a shortcut we can take to deconstruct the string into a table using one of the many variants of 0::

q)flip `field`value ! “S=\001” 0: fstring
field value
f1 “va”
f2 “vb”
f3 “vc”

Not only is this last example more succinct, it’s much faster:

q)\t do[100000;
flip `field`value !
@[flip "=" vs/: "\001" vs fstring; 0; `$]]
q)\t do[100000; flip `field`value ! "S=\001" 0: fstring]

See also How do I build a ctrl-A delimited string?

How do I build a ctrl-A delimited string?

Short answer: “\001” sv (“one”; “two”; “three”)

To build delimited strings in general, use the sv (scalar from vector) function:

q)”, ” sv (“Hello”; “world!”)
“Hello, world!”

As in many programming languages, the syntax for non-printable ASCII characters is borrowed from C, although only a subset of C’s sequences is supported:

\n      newline
\r      carriage return
\t      tab

(q also supports a few printable escape sequences: \\, \” and \’). However, as in C, you can express any ASCII code in q by following a backslash with the code’s 3 digit octal representation:

q)”\054\040″ sv (“Hello”; “world!”)
“Hello, world!”

Since ctrl-A is ASCII 1, we need to use \001:

q)fstring: “\001” sv (“f1=va”; “f2=vb”; “f3=vc”)

We can use 0: to write fstring to a file, and use an external program to confirm the result:

q)`:test 0: enlist fstring
$ hexdump test
0000000 66 31 3d 76 61 01 66 32 3d 76 62 01 66 33 3d 76
0000010 63 0a

To break fstring up into its parts, see How do I parse a ctrl-A delimited string?

How do I save a table to delimited text?

One way, if the format you want is csv, is automatically invoked when using the save function if the name of the destination file ends in .csv:

q)t: ([] x: `a`b; y: 1 2)
q)save `:t.csv
q)\cat t.csv

For other delimiters, you must first format the text using the overload of the 0: function whose first parameter is a character:

q)t: ([] x: `a`b; y: 1 2)
q)”|” 0: t

Notice that, by default, q saves the table column names as a header in the first line of the file. If you want to get rid of the header line, use _ (drop):

q)t: ([] x: `a`b; y: 1 2)
q)1 _ “\t” 0: t

Once you have your data as a list of strings complete with delimiters, you use another overload of the 0: function to save the data to disk; this time, the first parameter is the file handle (name) of the destination file:

q)t: ([] x: `a`b; y: 1 2)
q)`:filename.psv 0: 1 _ “|” 0: t
q)\cat filename.psv

Since we can’t seem to keep all of the overloads for 0: straight (there are more we didn’t cover here), we like to wrap the above idiom in a function with a descriptive name. For example,

SaveTableDataAsText: {[path; table; delimiter] hsym[path] 0: 1 _ delimiter 0: table}

See also:

This work is licensed under a Creative Commons License.
The views and opinions expressed herein are those of the authors and do not necessarily reflect those of any other person or legal entity.
Kdb+ is the registered trademark of Kx Systems, Inc.