8
\$\begingroup\$

Valve's KV file format is as follows (in pseudo-EBNF):

<pair> ::= <text> <value>
<value> ::= <text> | <block>
<text> ::= "\"" <char>* "\""
<block> ::= "{" <pair>* "}"

The parsing starts on <pair> state. Whitespace is allowed anywhere, but is only required between two consecutive <text> tokens ("a""b" is invalid, but "a" "b" is valid, and so is "a"{}).

And since I'm lazy, <char> is any character, except ", unless preceded by \.

You can also see KV as JSON without commas and colons, and with only strings and objects as possible types.

Your task is to write a program or function that converts a input string (stdin, file or argument) in KV to a output string in JSON. You can output anywhere (stdout, file or return value), as long as it's a valid json string.

It isn't necessary to preserve whitespace in the output, as long as quoted text doesn't change.

Standard loopholes apply, of course.

Bonus

You get a -20 byte bonus if the output is pretty-printed, regardless of input. Pretty printed means indenting each level of blocks with 4 spaces, separating colons from values by 1 space and have one pair per line. Closing braces should stand on their own line.

Test cases

Input:

"foo" {
    "bar" "baz"
    "oof" {
        "rab" "zab"
    }
}

Output:

{
    "foo": {
        "bar": "baz",
        "oof": {
            "rab": "zab"
        }
    }
}

Input:

"obj" {
    "emptyo" {}
    "troll" "}{"
}

Output:

{
    "obj": {
        "emptyo": {},
        "troll": "}{"
    }
}

Input:

"newline" "
"

Output:

{
    "newline": "\n"
}

Input:

"key
with_newline" {
    "\"escaped\"quotes" "escaped_end\""
}

Output:

{
    "key\nwith_newline": {
        "\"escaped\"quotes": "escaped_end\""
    }
}
\$\endgroup\$
16
  • \$\begingroup\$ In terms of the EBNF, what does the entire input need to be? \$\endgroup\$
    – feersum
    Nov 2, 2015 at 23:00
  • 2
    \$\begingroup\$ It's important to note that certain characters must be escaped in JSON strings. Since they aren't escaped in your KV format (I don't know whether your comment about laziness means that they are in the original KV spec), it's important to have some test cases which cover them. \$\endgroup\$ Nov 3, 2015 at 7:18
  • 1
    \$\begingroup\$ Also, your spec forces text to contain exactly one char, but all of your examples have texts with multiple chars. What should the spec say? 0 or more chars? 1 or more chars? \$\endgroup\$ Nov 3, 2015 at 7:22
  • 2
    \$\begingroup\$ So, when you say any character, do you mean Unicode, ASCII, printable ASCII and newlines, or something else? \$\endgroup\$
    – Dennis
    Nov 3, 2015 at 13:28
  • 1
    \$\begingroup\$ Also, you might want to include some test cases that involve backslashes and escaped double quotes. \$\endgroup\$
    – Dennis
    Nov 3, 2015 at 15:40

1 Answer 1

1
\$\begingroup\$

CJam, 57 54 bytes

{[~]2/{`_'{#{1>W<"\u%04x"fe%s`}{~J}?}f%':f*',*{}s\*}:J

This is a named function that pops a VDF string from the stack and pushes a JSON string in return.

CJam has no JSON built-ins, so the bonus won't be worth it. Since conditionally escaping some characters would be a pain for the same reason, I decided to escape everything.

The result isn't pretty, but it's valid JSON. Try it online in the CJam interpreter.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.