草庐IT

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

coder 2024-07-13 原文

我需要使用 gson 解码和编码字符串格式(这是一种 json 方言)。下面是我从 gson(Java) library 翻译过来的代码 由于某些原因,我尝试解码/替换的字符实际上都没有被替换。我相信我在字符转义方面做错了(我是新来的)所以任何方向/帮助修复它都将不胜感激。
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 \n %v \ngot \n %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",
    '\n': "\\n",
    '\r': "\\r",
    '\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['\n'] = "\\n";
    REPLACEMENT_CHARS['\r'] = "\\r";
    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. 您目前不会替换所有类型的以 \ 开头的转义组合,例如 \/

  2. const sdes 不是同一个字符串,不管你怎么解码它

  3. s 不包含有效的 JSON 编码字符串,因为 \x 序列无效。

无论如何,由于 gson 使用 JSON (RFC 7159),我建议使用现有的包来完成这项工作。试试 encoding/json:

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

附言。反对票很可能是因为您的问题很容易被视为代码审查,更适合 https://codereview.stackexchange.com

关于json - 如何将字符串编码/解码为 gson,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47454653/

有关json - 如何将字符串编码/解码为 gson的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  4. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  5. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

  6. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  7. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  10. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

随机推荐