Search code examples
gounicode-stringunicode-escapes

How to escape a string with single quotes


I am trying to unquote a string that uses single quotes in Go (the syntax is same as Go string literal syntax but using single quotes not double quotes):

'\'"Hello,\nworld!\r\n\u1F60ANice to meet you!\nFirst Name\tJohn\nLast Name\tDoe\n'

should become

'"Hello,
world!
😊Nice to meet you!
First Name      John
Last Name       Doe

How do I accomplish this?

strconv.Unquote doesn't work on \n newlines (https://github.com/golang/go/issues/15893 and https://golang.org/pkg/strconv/#Unquote), and simply strings.ReplaceAll(ing would be a pain to support all Unicode code points and other backslash codes like \n & \r & \t.

I may be asking for too much, but it would be nice if it automatically validates the Unicode like how strconv.Unquote might be able to do/is doing (it knows that x Unicode code points may become one character), since I can do the same with unicode/utf8.ValidString.


Solution

  • @CeriseLimón came up with this answer, and I just put it into a function with more shenanigans to support \ns. First, this swaps ' and ", and changes \ns to actual newlines. Then it strconv.Unquotes each line, since strconv.Unquote cannot handle newlines, and then reswaps ' and " and pieces them together.

    func unquote(s string) string {
            replaced := strings.NewReplacer(
                `'`,
                `"`,
                `"`,
                `'`,
                `\n`,
                "\n",
            ).Replace(s[1:len(s)-1])
            unquoted := ""
            for _, line := range strings.Split(replaced, "\n") {
                tmp, err := strconv.Unquote(`"` + line + `"`)
                repr.Println(line, tmp, err)
                if err != nil {
                    return nil, NewInvalidAST(obj.In.Text.LexerInfo, "*Obj.In.Text.Text")
                }
                unquoted += tmp + "\n"
            }
            return strings.NewReplacer(
                `"`,
                `'`,
                `'`,
                `"`,
            ).Replace(unquoted[:len(unquoted)-1])
    }