donglu9898
2017-11-23 11:39 阅读 102

如何将字符串编码/解码为gson

I need to decode and encode strings using the gson format (it's a json dialect). Below is the code I came up with so far translated from the gson(Java) library For some reasons none of the characters I try to decode/replace is actually replaced. I believe I'm doing something wrong with the character escaping(I'm new to go) so any direction/help to fix it would be appreciated.
Go Playground

 package main

import (
    "bytes"

    "fmt"
    "strings"
)

const s = `https:\/\/exampple.com\/static\/_\/js\/k\x3dgaia.gaiafe_glif.en.nnMHsIffkD4.O\/m\x3dglifb,identifier,unknownerror\/am\x3dggIgAAAAAAEKBCEImA2CYiCxoQo\/rt\x3dj\/d\x3d1\/rs\x3dABkqax3Fc8CWFtgWOYXlvHJI_bE3oVSwgA`
const des = `https://exampple.com/static/_/js/k=gaia.gaiafe_glif.en.nnMHsIffkD4.O/m=P9M9H,HUb4Ab,sy1m,sy1n,emo,sy1k,sy54,gsfs7c/am=ggIgAAAAAAEKBCEImA2CYiCxoQo/rt=j/d=0/rs=ABkqax3Fc8CWFtgWOYXlvHJI_bE3oVSwgA`

func main() {
    dec, err := Decode(s, true)
    if err != nil {
        panic(err)
    }
    if dec != des {
        fmt.Printf("expected 
 %v 
got 
 %s", dec, des)
    }
}

type replacementChar map[rune]string

func (r replacementChar) get(k rune) string {
    return fmt.Sprintf("\\u%04x", r[k])
}

var replacement = replacementChar{
    '"':  "\\\"",
    '\\': "\\\\",
    '\t': "\\t",
    '\b': "\\b",
    '
': "\
",
    '': "\",
    '\f': "\\f",
}
var htmlReplacement = replacementChar{
    '<':  "\\u003c",
    '>':  "\\u003e",
    '&':  "\\u0026",
    '=':  "\\u003d",
    '\'': "\\u0027",
}

var extraReplacement = replacementChar{
    '\u2028': "\\u2028",
    '\u2029': "\\u2029",
}

/*
 * From RFC 7159, "All Unicode characters may be placed within the
 * quotation marks except for the characters that must be escaped:
 * quotation mark, reverse solidus, and the control characters
 * (U+0000 through U+001F)."
 *
 * We also escape '\u2028' and '\u2029', which JavaScript interprets as
 * newline characters. This prevents eval() from failing with a syntax
 * error. http://code.google.com/p/google-gson/issues/detail?id=341
 */

func Encode(s string, htmlSafe bool) (string, error) {
    buf := bytes.NewBuffer([]byte("\""))
    var err error
    for _, r := range s {
        switch {
        case replacement[r] != "":
            _, err = buf.WriteString(replacement.get(r))
            if err != nil {
                return "", err

            }
        case htmlSafe && htmlReplacement[r] != "":
            _, err = buf.WriteString(htmlReplacement.get(r))
            if err != nil {
                return "", err

            }
        case extraReplacement[r] != "":
            _, err = buf.WriteString(extraReplacement.get(r))
            if err != nil {
                return "", err

            }
        default:
            _, err = buf.WriteRune(r)
            if err != nil {
                return "", err

            }
        }
    }
    buf.WriteString("\"")
    return buf.String(), nil
}

var decodeHTMLReplacementPair []string
var decodeReplacementPair []string
var decodeReplacementAll []string

func init() {
    for k, _ := range htmlReplacement {
        decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, htmlReplacement.get(k))
        decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, string(k))

    }
    for k, _ := range replacement {
        decodeReplacementPair = append(decodeReplacementPair, replacement.get(k))
        decodeReplacementPair = append(decodeReplacementPair, string(k))

    }
    for k, _ := range extraReplacement {
        decodeReplacementPair = append(decodeReplacementPair, extraReplacement.get(k))
        decodeReplacementPair = append(decodeReplacementPair, string(k))

        decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, extraReplacement.get(k))
        decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, string(k))

    }
    decodeReplacementAll = append(decodeHTMLReplacementPair, decodeReplacementPair...)

}

func Decode(s string, htmlSafe bool) (string, error) {
    var r *strings.Replacer
    if !htmlSafe {
        r = strings.NewReplacer(decodeHTMLReplacementPair...)
    } else {
        r = strings.NewReplacer(decodeReplacementAll...)
    }

    return r.Replace(s), nil
}

/* Original Java Source https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/stream/JsonWriter.java
  private static final String[] REPLACEMENT_CHARS;
  private static final String[] HTML_SAFE_REPLACEMENT_CHARS;
  static {
    REPLACEMENT_CHARS = new String[128];
    for (int i = 0; i <= 0x1f; i++) {
      REPLACEMENT_CHARS[i] = String.format("\\u%04x", (int) i);
    }
    REPLACEMENT_CHARS['"'] = "\\\"";
    REPLACEMENT_CHARS['\\'] = "\\\\";
    REPLACEMENT_CHARS['\t'] = "\\t";
    REPLACEMENT_CHARS['\b'] = "\\b";
    REPLACEMENT_CHARS['
'] = "\
";
    REPLACEMENT_CHARS[''] = "\";
    REPLACEMENT_CHARS['\f'] = "\\f";
    HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone();
    HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c";
    HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e";
    HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026";
    HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d";
    HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027";
}


private void string(String value) throws IOException {
    String[] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS;
    out.write("\"");
    int last = 0;
    int length = value.length();
    for (int i = 0; i < length; i++) {
      char c = value.charAt(i);
      String replacement;
      if (c < 128) {
        replacement = replacements[c];
        if (replacement == null) {
          continue;
        }
      } else if (c == '\u2028') {
        replacement = "\\u2028";
      } else if (c == '\u2029') {
        replacement = "\\u2029";
      } else {
        continue;
      }
      if (last < i) {
        out.write(value, last, i - last);
      }
      out.write(replacement);
      last = i + 1;
    }
    if (last < length) {
      out.write(value, last, length - last);
    }
    out.write("\"");
}

*/
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    doulu7921 doulu7921 2017-11-23 13:31
    1. You are currently not replacing all kinds of escape combinations that would start with \, such as \/.

    2. const s and des are not the same strings, no matter how you decode it

    3. s does not contain a valid JSON encoded string as \x sequences are not valid.

    Anyhow, since gson uses JSON (RFC 7159), I suggest using an existing package for this work. Try encoding/json:

    func main() {
        var dec string
        err := json.Unmarshal([]byte(`"`+s+`"`), &dec)
        if err != nil {
            panic(err)
        }
        if dec != des {
            fmt.Printf("expected 
     %v 
    got 
     %s", dec, des)
        }
    }
    

    PS. The downvotes are most likely because your question can easily be considered code review, being more suitable for https://codereview.stackexchange.com

    点赞 评论 复制链接分享

相关推荐