【问题标题】:Replace part of the String by Regular Expression用正则表达式替换部分字符串
【发布时间】:2017-11-27 06:36:41
【问题描述】:

我的字符串输入类似于:

{"key1":"value1","key2":"{\"key2_1\":\"123\",\"key2_2\":\"456\",\"key2_3\":\"33333\"}"}

上述JSON中的值字段可以包含"、\等字符。为了您的方便,这里是格式化的版本:

{
    "key1": "value1",
    "key2": "{\"key2_1\":\"123\",\"key2_2\":\"456\",\"key2_3\":\"33333\"}"
}

我想使用 Gson 将 String 转换为 Foo 对象:

class Foo {
    private String key1;
    private Bar key2;
    ...
}

class Bar {
    private String key2_1;
    private String key2_2;
    private String key2_3;
    ...
}

这是我的正则表达式:

String regexp = "\\{[\"a-zA-Z-0-9:,\\\\]*\"key2\":\"\\{\\\\\"key2_1\\\\\":\\\\\"[a-zA-Z0-9]*\\\\\",\\\\\"key2_2\\\\\":\\\\\"[a-zA-Z0-9]*\\\\\",\\\\\"key2_3\\\\\":\\\\\"[a-zA-Z0-9]*\\\\\"\\}\"\\}[\"a-zA-Z-0-9:,\\\\]*";
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(text);
if(matcher.matches()) {
    ... // TODO: Replace all "{, \" and }" but How???
}

如何使用这个正则表达式将所有"{、\".和"}替换为{、"、}而不更改JSON中的键和值?

找到子字符串并使用String的替换方法将是我的备用解决方案。

同样,我的最终目标是将输入字符串解析为我的 Foo 对象。有没有比使用正则表达式更好的方法?

谢谢!

【问题讨论】:

  • 不应该像这样正常工作吗?
  • @Shark Matcher 只返回一个布尔值。我无法通过“就像这样”将字符串转换为对象。请注意 key2 的输入值是一个字符串,而 Foo 对象中对应的字段是 Bar 对象。
  • 我的意思是,JSON 已经包含一个Bar 对象;它不应该解析成Foo 实例吗?
  • @Shark JSON 包含一个用于 Bar 对象的字符串,而不是普通的 JSON 对象。将 String 直接解析为 Foo 对象会引发错误。

标签: java json regex gson


【解决方案1】:

进一步挖掘后,我找到了这两个链接:

Gson custom deseralizer for one variable in an object

Gson custom seralizer for one variable (of many) in an object using TypeAdapter

我通过将自己的JsonDeserializer 注册到GsonBuilder 实现了我想要的:

private static GsonBuilder gsonBuilder = new GsonBuilder().registerTypeAdapter(Bar.class, new JsonDeserializer<Bar>() {

    @Override
    public Bar deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException {
        Bar result = new Bar();
        String regexp = "\"\\{\\\\\"key2_1\\\\\":\\\\\"(?s).*\\\\\".\\\\\"key2_2\\\\\":\\\\\"(?s).*\\\\\",\\\\\"key2_3\\\\\":\\\\\"(?s).*\\\\\"\\}\"";
        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(json.toString());
        String modifiedJsonStr = json.toString();
        if(matcher.matches()) {
            modifiedJsonStr = json.toString().replace("\"{", "{").replace("}\"", "}").replace("\\\"", "\"");
        }
        result = new Gson().fromJson(modifiedJsonStr, Bar.class);
        return result;
    }
});

干杯。

【讨论】:

    【解决方案2】:

    黄金法则是不要对此类事情使用正则表达式 :) 我的建议是过于关注 JSON 映射器,例如 Jackson

    所有你需要做的:

    1. 在您的示例中修复 JSON,这里不需要在嵌套 {
    2. 周围加上双引号
    3. 添加 Jackson 依赖项

      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>${jackson.version}</version>
      </dependency>
      
    4. 创建ObjectMapper,让他处理你的JSON字符串

      ObjectMapper mapper = new ObjectMapper();
      Foo foo = mapper.readValue( "{\"key1\":\"value1\",\"key2\":"
           + " {\"key2_1\":\"123\",\"key2_2\":\"456\",\"key2_3\":\"33333\"}}", Foo.class);
      System.out.println(foo.toString());
      

    希望对你有帮助!

    【讨论】:

    • 问题是输入的 JSON 不在我的控制之下 :(
    • @Top.Deck 这不是问题,该解决方案适用于任何有效的 JSON 输入。嵌套的特殊字符将被正确处理。
    • 代码中的输入实际上是 "{\"key1\":\"value1\",\"key2\":" + " {\\\"key2_1\\\": \\\"123\\\",\\\"key2_2\\\":\\\"456\",\\\"key2_3\\\":\\\"33333\\\"}}" ,因此代码认为 key2 具有 String 值而不是嵌套的 JSON。
    • @Top.Deck 我的代码输出将是 Foo [key1=value1, key2=Bar [key2_1=123, key2_2=456, key2_3=33333]] 。我想这是你的期望,根据显示的 dao 类。
    • 我完全同意你的观点,你的输出就是我想要的对象。但是您的输入在这里有点错误。您的输入是嵌套的 JSON,而我的 key2 包含一个字符串。您能否将代码中的 Foo foo 行替换为 Foo foo = mapper.readValue("{\"key1\":\"value1\",\"key2\":" + " {\\\"key2_1\\\ ":\\\"123\\\",\\\"key2_2\\\":\\\"456\",\\\"key‌​2_3\\\":\\\"33333\\\ ‌​“}}”);看看输出是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    相关资源
    最近更新 更多