# CSV/TSV Implementation in mq
# Based on RFC 4180 for CSV format
def csv_needs_quote(field, delimiter):
let s = to_string(field)
| contains(s, "\"") || contains(s, "\n") || contains(s, "\r") || contains(s, delimiter) || starts_with(s, " ") || ends_with(s, " ")
end
# Parses CSV content with a specified delimiter and optional header row.
def csv_parse_with_delimiter(input, delimiter, has_header): _csv_parse(input, delimiter, has_header);
# Parses CSV content using a comma as the delimiter.
def csv_parse(input, has_header): _csv_parse(input, ",", has_header);
# Parses TSV (Tab-Separated Values) content.
def tsv_parse(input, has_header): _csv_parse(input, "\t", has_header);
# Parses PSV (Pipe-Separated Values) content.
def psv_parse(input, has_header): _csv_parse(input, "|", has_header);
# Converts data to a CSV string with a specified delimiter.
def csv_stringify(data, delimiter):
let headers = if (is_array(data) && len(data) > 0 && is_dict(first(data))):
keys(first(data))
else: first(data)
| let header_line = join(headers, delimiter)
| let data = if (is_dict(first(data))): data else: data[1:len(data)]
| let process_row = fn(row):
if (is_dict(row)):
join(map(headers, fn(header):
if (row[header]):
if (csv_needs_quote(row[header], delimiter)):
"\"" + to_string(row[header]) + "\""
else:
to_string(row[header])
else:
"";), delimiter)
else:
join(map(row, fn(field):
let s = to_string(field)
| if (csv_needs_quote(field, delimiter)):
s"\"${s}\""
else: s;), delimiter)
end
| let data_lines = map(data, process_row)
| [header_line] + data_lines
| join("\n")
end
# Converts CSV data to a Markdown table format.
def csv_to_markdown_table(data):
let headers = if (is_array(data) && len(data) > 0 && is_dict(first(data))):
keys(first(data))
else: first(data)
| let header_row = "| " + join(headers, " | ") + " |"
| let separator_row = "| " + join(map(headers, fn(_): "---";), " | ") + " |"
| let data = if (is_dict(first(data))): data else: data[1:len(data)]
| let data_rows = map(data, fn(row):
if (is_dict(row)):
"| " + join(map(headers, fn(header): if (row[header]): to_string(row[header]) else: "";), " | ") + " |"
else:
"| " + join(map(row, to_string), " | ") + " |"
end)
| [header_row, separator_row] + data_rows
| join("\n")
end
# Converts CSV data to a JSON string.
def csv_to_json(data):
def _to_json(value):
if (is_dict(value)):
"{" + join(map(keys(value), fn(k): "\"" + k + "\":" + _to_json(value[k]);), ",") + "}"
elif (is_array(value)):
"[" + join(map(value, _to_json), ",") + "]"
elif (is_string(value)):
"\"" + replace(replace(value, "\"", "\\\""), "\n", "\\n") + "\""
elif (is_number(value)):
to_string(value)
elif (is_bool(value)):
if (value): "true" else: "false"
elif (is_none(value)):
"null"
else:
"\"" + to_string(value) + "\""
end
| if (is_array(data) && len(data) > 0 && is_dict(first(data))):
_to_json(data)
else:
_to_json(map(data, fn(row): row;))
end