The challenge is to parse a string like Python does and print the contents of the string.

  • Input (command-line argument or stdin): a string literal (e.g. "hello") (or multiple literals, see string literal concatenation below)
  • Output (stdout): the contents of the string (e.g. hello)

Rules for parsing the string:

  • A string literal is enclosed in matching pairs of single quotes ('a'), double quotes ("a"), triple single quotes ('''a''') or triple double quotes ("""a"""). The first reoccurrence of the type of quotes that opened the string ends the string.
  • Backslash escapes: \' within a string becomes ', \" becomes " and \\ becomes \. You do not need to implement any other backslash escapes. A backslash that is not part of an escape sequence stays a backslash.
  • String literal concatenation: The contents of adjacent string literals are concatenated. For example, "hello" 'world' becomes helloworld.
  • The input may contain spaces that are not part of any literal.
  • You do not need to support any other kind of whitespace, neither within nor outside literals.

Additional rules:

  • eval, exec and similar stuff is not allowed for parsing the literal or parts of it.
  • You may assume that the input is valid.
  • You may assume a maximum input length of 1023 characters.


  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (without parentheses, but with spaces) -> """'''

Shortest code wins.

  • \$\begingroup\$ Is the output to be of a form that can be stored, or is it sufficient to print it and be done with it? \$\endgroup\$
    – DavidC
    Commented Jul 18, 2013 at 22:12
  • \$\begingroup\$ @David Printing it is all you need to do. \$\endgroup\$
    – flornquake
    Commented Jul 18, 2013 at 22:22
  • \$\begingroup\$ So in (e.g.) "\z", the code is specifically required to output the backslash and the z? But \' becomes just an apostrophe, even if it appears inside double-quotes or triple-quotes? Is that correct? \$\endgroup\$
    – breadbox
    Commented Jul 18, 2013 at 23:49
  • \$\begingroup\$ @breadbox Exactly. \$\endgroup\$
    – flornquake
    Commented Jul 19, 2013 at 0:13
  • \$\begingroup\$ Should the code support raw strings? And what about concatenation of non-raw and raw strings? \$\endgroup\$
    – Bakuriu
    Commented Jul 19, 2013 at 18:28

3 Answers 3


Perl, 54 characters

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

Just as I was posting this, I noticed that it's almost identical to Jan Dvorak's Ruby solution. I'm a little put out by how similar it is, in fact, but I'm going to say "Great minds think alike" and let it go at that.

This program highlights a weird corner case in counting characters in Perl scripts: By my reading, the presence of single-quotes in the script means that I need to count the -p option as two characters towards my total. Typically, when computing Perl script sizes, the initial dash character on the options is considered to be free, on the justification that it can be bundled with the -e that introduces the program proper ... but then you also have to account for any extra escapes you need to enter the script on the command-line. The single-quotes require lots of escaping, so to avoid that penalty I have to count it as a script run from a file, and therefore I get the #!/usr/bin/perl for free, but not any option characters. It's a little confusing.

  • 2
    \$\begingroup\$ If you want to be different, (('|")\2{2}?) is the same length as ("""|'''|"|') \$\endgroup\$ Commented Jul 19, 2013 at 17:16

C, 178 characters


This is one of those C solutions where everything is done inside a ternary-operator chain gang.

The program works by copying characters back into the same buffer, overwriting the metacharacters. d holds the delimiter when inside of a string, and t is true if the delimiter is a triple-quote.

  • \$\begingroup\$ I think you need to include a conditional extra incrementation of the loop control variable. For 'foo\\'bar' it gives foo\ar', which looks like it replaces \\ with \, but then continues the parsing with the freshly entered \, seeing the next token as \'. \$\endgroup\$
    – manatwork
    Commented Jul 19, 2013 at 7:32
  • \$\begingroup\$ Actually, that example is invalid input. 'foo\\' refers to the string foo\, which is then followed by a character that is neither whitespace nor a string delimiter. \$\endgroup\$
    – breadbox
    Commented Jul 19, 2013 at 7:34
  • \$\begingroup\$ Oops. I misread that rule. Then of course your code is correct. \$\endgroup\$
    – manatwork
    Commented Jul 19, 2013 at 7:41

Ruby, 74 73 characters

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

The core here are two regexes: The first one determines the string boundaries and selects the contents only. The alteration is there to remove everything not inside strings, and it also drops unclosed strings. Backslashes are treated as possesive-optional followed by anything. Thus, Since the regex engine will not backtrack into (\\?.) for valid inputs (thanks @breadbox), a sole backslash cannot match there. Quotes are handled via lazy repetition. The second regex then strips a backslash before each escapeable character. The regex depends on the engine to always pick the leftmost alternative first.

I have also considered a state-machine approach, but it turned out quite big (19 states x 4 character classes) compared to the regex solution. I can still post the state machine if anyone is interested.

  • \$\begingroup\$ One minor glitch with this method: 'foo\\'bar' becomes foo\ instead of 'foo\'bar'. \$\endgroup\$
    – manatwork
    Commented Jul 19, 2013 at 7:24
  • \$\begingroup\$ @manatwork this is correct, unless something has been lost in formatting. The first backslash escapes the second one. 'foo\\' is the first string and bar' is outside a string context when the input is 'foo\\'bar' \$\endgroup\$ Commented Jul 19, 2013 at 7:29
  • \$\begingroup\$ Oops. No idea how I calculated it earlier. Of course it is correct. Sorry. \$\endgroup\$
    – manatwork
    Commented Jul 19, 2013 at 7:35
  • \$\begingroup\$ When I try to run this I get an error message: "nested *?+ in regexp". Is there some minimum version or runtime flag that I need? \$\endgroup\$
    – breadbox
    Commented Jul 19, 2013 at 16:28
  • \$\begingroup\$ @breadbox I haven't checked other versions, but I'm running ruby 1.9.3 (JRuby 1.7.2). should I assume 1.9.3 at least and edit that in? \$\endgroup\$ Commented Jul 19, 2013 at 16:32

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.