镜之Json Compare Diff

news2024/11/24 18:33:35

前言

“镜” 寓意是凡事都有两面性,Json 对比也不例外!

因公司业务功能当中有一个履历的功能,它有多个版本的 JSON 数据需要对比出每个版本的不同差异节点并且将差异放置在一个新的 JSON 当中原有结构不能变动,差异节点使用数组对象的形式存储,前端点击标红即可显示多个版本的节点差异数据如下图

banner
banner
履历查看
履历查看

示例

// JSON One
{
    "employee":
    {
        "id""1212",
        "fullName":"John Miles",
        "age"34,
        "contact":
        {
            "email""john@xyz.com",
            "phone""9999999999"
        }
    }
}

// Json Two
{
    "employee":
    {
        "id""1212",
        "ae86""12162",
        "age"34,
        "fullName""John Miles111",
        "contact":
        {
            "email""john@xyz.com",
            "phone""我是改了的",
            "668""999999991199"
        }
    }
}

可以看到 employee.ae86 是新增的。contact.668 也是新增的 phone 字段是修改了的

对比后的 Json

// 获取差异的节点 使用数组对象表示
{
 "employee/fullName/": [{
  "old""John Miles"
 }, {
  "new""John Miles111"
 }],
 "employee/contact/phone/": [{
  "old""9999999999"
 }, {
  "new""我是改了的"
 }],
 "employee/contact/668": [{
  "new""999999991199"
 }],
 "employee/ae86": [{
  "new""12162"
 }]
}

// 将差异节点的数据覆盖上去

{
  "employee" : {
    "id" : "1212",
    "fullName" : [ {
      "old" : "John Miles"
    }, {
      "new" : "John Miles111"
    } ],
    "age" : 34,
    "contact" : {
      "email" : "john@xyz.com",
      "phone" : [ {
        "old" : "9999999999"
      }, {
        "new" : "我是改了的"
      } ],
      "668" : [ {
        "new" : "999999991199"
      } ]
    },
    "ae86" : [ {
      "new" : "12162"
    } ]
  }
}

实现

一、得到差异点 Map

package com.yby6;


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.ObjectUtils;

import java.io.IOException;
import java.util.*;

/**
 * @author Yang Shuai
 * Create By 2023/8/26
 */


public class JsonComparerUtils2 {
    static ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) {

        String s1 = "{ \n" +
                "    \"employee\":\n" +
                "    {\n" +
                "        \"id\": \"1212\",\n" +
                "        \"fullName\":\"John Miles\",\n" +
                "        \"age\": 34,\n" +
                "        \"contact\":\n" +
                "        {\n" +
                "            \"email\": \"john@xyz.com\",\n" +
                "            \"phone\": \"9999999999\"\n" +
                "        }\n" +
                "    }\n" +
                "}";
        String s2 = "{\n" +
                "    \"employee\":\n" +
                "    {\n" +
                "        \"id\": \"1212\",\n" +
                "        \"ae86\": \"12162\",\n" +
                "        \"age\": 34,\n" +
                "        \"fullName\": \"John Miles111\",\n" +
                "        \"contact\":\n" +
                "        {\n" +
                "            \"email\": \"john@xyz.com\",\n" +
                "            \"phone\": \"我是改了的\",\n" +
                "            \"668\": \"999999991199\"\n" +
                "        }\n" +
                "    }\n" +
                "}";
        try {

            // 将json转Json节点树
            JsonNode node1 = mapper.readTree(s1);
            JsonNode node2 = mapper.readTree(s2);

            List<String> ignoreKey = new ArrayList<>();

            // 获取两个JSON之间的差异
            Map<String, Object> nodesDiff = getNodesDiff(node1, node2,
                    "", ignoreKey);
            System.out.println(mapper.writeValueAsString(nodesDiff));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    /**
     * 得到节点差异
     *
     * @param node1     node1
     * @param node2     node2
     * @param path      路径
     * @param ignoreKey 忽略关键
     * @return {@link Map}<{@link String}, {@link Object}>
     */

    private static Map<String, Object> getNodesDiff(JsonNode node1, JsonNode node2, String path, List<String> ignoreKey) {
        Map<String, Object> diff = new LinkedHashMap<>();

        String[] split = path.split("/");
        String filed = split[split.length - 1];


        if (!node1.getNodeType().equals(node2.getNodeType())) {
            addToMap(path, node1, node2, diff, "update");
        } else {
            switch (node1.getNodeType()) {
                case OBJECT:

                    if (node1.isObject() && !node1.isEmpty()) {
                        for (Iterator<String> it = node1.fieldNames(); it.hasNext(); ) {
                            String fieldName = it.next();

                            JsonNode childNode1 = node1.get(fieldName);
                            JsonNode childNode2 = node2.get(fieldName);

                            // 忽略指定字段不对比
                            if (ignoreKey.contains(fieldName)) {
                                continue;
                            }

                            if (childNode2 != null) {
                                Map<String, Object> nestedDiff = getNodesDiff(childNode1, childNode2, path + fieldName + "/", ignoreKey);
                                if (!nestedDiff.isEmpty()) {
                                    diff.putAll(nestedDiff);
                                }
                            } else {
                                // 旧的存在新的则不存在表示删除
                                addToMap(path + fieldName, childNode1, childNode1, diff, "delete");
                            }
                        }

                        for (Iterator<String> it = node2.fieldNames(); it.hasNext(); ) {
                            String fieldName = it.next();
                            if (ignoreKey.contains(fieldName)) {
                                continue;
                            }
                            // 如果旧的没有这个数据那么表示新增
                            if (node1.get(fieldName) == null) {
                                addToMap(path + fieldName, null, node2.get(fieldName), diff, "add");
                            }
                        }
                    }


                    break;
                case ARRAY:
                    // 判断两个数组的长度不一样则需要将两个数组的长度补齐
                    if (node1.size() > 0 && node2.size() > 0 && node1.size() != node2.size()) {

                        try {
                            String m1 = mapper.writeValueAsString(node1);
                            String m2 = mapper.writeValueAsString(node2);

                            List list1 = mapper.readValue(m1, List.class);
                            List list2 = mapper.readValue(m2, List.class);


                            if (list1.size() > list2.size()) {

                                for (int i = list2.size(); i < list1.size(); i++) {
                                    String o = mapper.writeValueAsString(list1.get(i));
                                    JsonNode jsonNode = mapper.readTree(o);
                                    // 清空的
                                    clearNodeValues(jsonNode, ignoreKey);
                                    // 将jsonNode2添加到jsonNode1中
                                    ((ArrayNode) node2).add(jsonNode);
                                }
                            } else {
                                for (int i = list1.size(); i < list2.size(); i++) {
                                    String o = mapper.writeValueAsString(list2.get(i));
                                    JsonNode jsonNode = mapper.readTree(o);
                                    // 清空的
                                    clearNodeValues(jsonNode, ignoreKey);
                                    ((ArrayNode) node1).add(jsonNode);
                                }
                            }


                            // 排序数组

                            List<JsonNode> firstList = mapper.readValue(node1.traverse(), new TypeReference<List<JsonNode>>() {
                            });
                            List<JsonNode> secondList = mapper.readValue(node2.traverse(), new TypeReference<List<JsonNode>>() {
                            });


                            // 补齐后递归对比
                            for (int i = 0; i < firstList.size(); i++) {
                                Map<String, Object> nestedDiff = getNodesDiff(firstList.get(i), secondList.get(i), path + "[" + i + "]/", ignoreKey);
                                if (!nestedDiff.isEmpty()) {
                                    diff.putAll(nestedDiff);
                                }
                            }


                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }

                    } else {
                        // 判断数组里面是不是对象
                        if (node1.size() > 0 && node1.get(0).getNodeType().equals(JsonNodeType.OBJECT)) {
                            for (int i = 0; i < node1.size(); i++) {
                                if (ignoreKey.contains(filed)) {
                                    break;
                                }
                                Map<String, Object> nestedDiff = getNodesDiff(node1.get(i), node2.get(i), path + "[" + i + "]/", ignoreKey);
                                if (!nestedDiff.isEmpty()) {
                                    diff.putAll(nestedDiff);
                                }
                            }
                        } else {
                            if (!node1.equals(node2)) {
                                if (ignoreKey.contains(filed)) {
                                    break;
                                }
                                addToMap(path, node1, node2, diff, "update");
                            }
                        }
                    }
                    break;
                case STRING:
                case BOOLEAN:
                case NUMBER:
                    if (ignoreKey.contains(filed)) {
                        break;
                    }

                    // 如果新的为空则为删除
                    if (ObjectUtils.isEmpty(node2)) {
                        addToMap(path, node1, node2, diff, "delete");
                    }

                    if (!node1.equals(node2)) {
                        addToMap(path, node1, node2, diff, "update");
                    }

                    break;
                default:
                    throw new IllegalArgumentException("Unsupported JSON type:" + node1.getNodeType().name());
            }
        }

        return diff;
    }


    /**
     * 清空节点参数
     *
     * @param node 节点
     */

    private static void clearNodeValues(JsonNode node, List<String> ignoreKey) {
        // 忽略部分清空
        if (node.isObject()) {
            ObjectNode objectNode = (ObjectNode) node;
            objectNode.fields().forEachRemaining(entry -> {
                if (!ignoreKey.contains(entry.getKey())) {
                    objectNode.replace(entry.getKey(), null);
                }
            });
        } else if (node.isArray()) {
            for (JsonNode childNode : node) {
                clearNodeValues(childNode, ignoreKey);
            }
        }
    }


    /**
     * 将两个json的差异添加到Map
     *
     * @param path     路径
     * @param oldValue 旧值
     * @param newValue 新值
     * @param diff     diff
     */

    private static void addToMap(String path, JsonNode oldValue, JsonNode newValue, Map<String, Object> diff, String diffType) {
        List<Object> values = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        map.put("old", oldValue != null ? getContent(oldValue) : "");
        map.put("new", newValue != null ? getContent(newValue) : "");
        map.put("diffType", diffType);
        values.add(map);
        diff.put(path, values.toArray(new Object[0]));
    }

    /**
     * 获取内容
     *
     * @param node 节点
     * @return {@link Object}
     */

    private static Object getContent(JsonNode node) {
        if (node.isBoolean()) {
            return node.asBoolean();
        } else if (node.isNumber()) {
            return node.asInt();
        } else if (node.isTextual()) {
            return node.asText();
        } else if (node.isObject()) {
            Map<String, Object> obj = new LinkedHashMap<>();
            for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
                String propName = it.next();
                obj.put(propName, getContent(node.get(propName)));
            }
            return obj;
        } else if (node.isArray()) {
            ArrayNode array = (ArrayNode) node;
            Object[] contents = new Object[array.size()];
            for (int i = 0; i < array.size(); i++) {
                contents[i] = getContent(array.get(i));
            }
            return contents;
        } else if (node.isNull()) {
            return null;
        } else {
            throw new UnsupportedOperationException("不支持的 JSON 类型:" + node.getNodeType().name());
        }
    }

测试输出

测试
测试
{
 "employee/fullName/": [{
  "new""John Miles111",
  "old""John Miles",
  "diffType""update"
 }],
 "employee/contact/phone/": [{
  "new""我是改了的",
  "old""9999999999",
  "diffType""update"
 }],
 "employee/contact/668": [{
  "new""999999991199",
  "old""",
  "diffType""add"
 }],
 "employee/ae86": [{
  "new""12162",
  "old""",
  "diffType""add"
 }]
}

获取差异代码讲解

这段代码是一个处理两个 JSON 节点之间差异的方法,以及一些辅助方法。下面我将解释每个方法的作用和代码逻辑:

getNodesDiff 方法

描述

该方法用于比较两个 JSON 节点(node1node2)之间的差异,包括子节点差异,并返回一个表示差异的 Map

方法签名

private static Map<String, Object> getNodesDiff(JsonNode node1, JsonNode node2, String path, List<String> ignoreKey)

代码解释

  • diff 是一个用于存储差异的 LinkedHashMap
  • 首先,它根据路径 path 中的最后一个部分( field)来确定节点的类型。
  • 然后,它检查 node1node2 的节点类型是否相同,如果不同,将差异添加到 diff 中。
  • 如果节点类型相同,则根据节点类型进行处理,包括对象、数组、字符串、布尔值和数字类型。
  • 对于对象类型,它递归地比较对象的字段,同时考虑了一些特殊情况,例如忽略指定的字段和 isValid 字段为 0 的情况。
  • 对于数组类型,它首先检查数组长度是否不一致,如果不一致,则尝试将两个数组的长度补齐,然后递归比较数组元素。如果数组元素是对象类型,也会递归比较对象。
  • 对于其他基本数据类型,它会直接比较节点的值,如果不同,将差异添加到 diff 中。

clearNodeValues 方法

描述

这是一个辅助方法,用于清空节点的值,但保留节点结构。

方法签名

private static void clearNodeValues(JsonNode node, List<String> ignoreKey)

代码解释

  • 如果节点是对象类型,则清空对象中指定的字段,但忽略 ignoreKey 中的字段。
  • 如果节点是数组类型,则递归地清空数组元素的值,但保留数组结构。

addToMap 方法

描述

这是一个辅助方法,用于将差异信息添加到差异 Map 中。

方法签名

private static void addToMap(String path, JsonNode oldValue, JsonNode newValue, Map<String, Object> diff, String diffType)

代码解释

  • 该方法将差异信息以指定的格式添加到 diff 中,包括路径 path、旧值 oldValue、新值 newValue 和差异类型 diffType

getContent 方法

描述

这是一个辅助方法,用于从 JsonNode 中提取内容。

方法签名

private static Object getContent(JsonNode node)

代码解释

  • 该方法根据 JsonNode 的类型提取内容,可能是布尔值、整数、字符串、对象、数组或 null 值。
  • 对于对象和数组类型,它递归提取内容并返回。

二、合并

    /**
     * 将差异应用到指定的 JSON 字符串,并返回处理后的字符串。
     *
     * @param json 要应用差异的原始 JSON 字符串
     * @param diff 差异内容,即 {@link #getNodesDiff} 返回的 Map 对象
     * @return 经过差异处理后的 JSON 字符串
     */

    public static String applyDiff(String json, Map<String, Object> diff) throws IOException {
        JsonNode node = mapper.readTree(json);
        for (Map.Entry<String, Object> entry : diff.entrySet()) {
            String[] path = entry.getKey().split("/");
            JsonNode parentNode = node;
            for (int i = 0; i < path.length - 1; i++) {
                // 如果是null则跳过
                if (parentNode == null) {
                    continue;
                }
                // 如果该节点是数组那么解析一下
                if (parentNode.isArray()) {
                    int index = getIndexFromPath(path[i]);
                    parentNode = parentNode.get(index);
                } else {
                    parentNode = parentNode.get(path[i]);
                }
            }

            // 如果拿到的父节点是null则跳过
            if (parentNode == null) {
                continue;
            }

            String propertyName = path[path.length - 1];
            JsonNode childNode = parentNode.get(propertyName);


            if (entry.getValue() == null) {
                if (parentNode.isArray()) {
                    ((ArrayNode) parentNode).remove(Integer.parseInt(propertyName.substring(1, propertyName.length() - 1)));
                } else {
                    ((ObjectNode) parentNode).remove(propertyName);
                }
            } else {
                Object value = entry.getValue();
                // 是否是数组
                if (ArrayUtil.isArray(value)) {
//                    ArrayNode arrayNode = mapper.createArrayNode(); // 新建一个空的数组节点
//                    arrayNode.addPOJO(value);
                    ObjectMapper objectMapper = new ObjectMapper();
                    JsonNode arrayNode = objectMapper.valueToTree(value);
//                    Object[] arr = (Object[]) value;
//                    for (Object item : arr) {
//                        if (item != null) {
//                            // 将数组元素依次加入新建的数组节点中,不需要处理逗号问题
//                            arrayNode.addPOJO(item);
//                        }
//                    }
                    if (childNode != null && !childNode.isMissingNode()) { // 已经存在该属性,需要替换
                        ((ObjectNode) parentNode).replace(propertyName, arrayNode);
                    } else { // 不存在该属性,直接应用差异
                        // 如果父节点是数组,在数组末尾添加新元素
                        // 如果父节点是对象,在该对象中添加新属性,值为空
                        if (parentNode.isArray()) {
                            int position = 0;
                            if (StringUtils.isNotBlank(propertyName)) {
                                position = Integer.parseInt(propertyName.substring(1, propertyName.length() - 1));
                            }

                            while (position > parentNode.size()) {
                                ((ArrayNode) parentNode).add(mapper.createObjectNode().put(""""));
                            }
                            ((ArrayNode) parentNode).add(arrayNode);
                        } else {
                            ((ObjectNode) parentNode).set(propertyName, arrayNode);
                        }
                    }
                } else {
                    String newValue = entry.getValue().toString();
                    if (childNode == null || childNode.isNull() || childNode.isMissingNode()) {
                        if (parentNode.isArray()) { // 如果父节点是数组,在数组末尾添加新元素
                            ((ArrayNode) parentNode).add(mapper.createObjectNode().put(propertyName, ""));
                        } else { // 如果父节点是对象,在该对象中添加新属性,值为空
                            ((ObjectNode) parentNode).put(propertyName, "");
                        }
                        childNode = parentNode.get(propertyName);
                    }
                    if (childNode.isValueNode()) {
                        if (childNode.isBoolean()) {
                            ((ObjectNode) parentNode).put(propertyName, Boolean.parseBoolean(newValue));
                        } else if (childNode.isIntegralNumber()) {
                            ((ObjectNode) parentNode).put(propertyName, newValue);
                        } else if (childNode.isFloatingPointNumber()) {
                            ((ObjectNode) parentNode).put(propertyName, Double.parseDouble(newValue));
                        } else if (childNode.isTextual()) {
                            try {
                                ((ObjectNode) parentNode).put(propertyName, newValue.substring(1, newValue.length() - 1)); // 去掉 JSON 字符串外层的双引号
                            } catch (Exception e) {
                                ((ObjectNode) parentNode).put(propertyName, newValue);
                            }
                        }
                    } else {
                        ((ObjectNode) parentNode).set(propertyName, mapper.readTree(newValue));
                    }
                }
            }
        }
        return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
    }


    /**
     * 移除方括号并将剩余字符串解析为整数索引
     *
     * @param path 路径
     * @return int
     */

    private static int getIndexFromPath(String path) {
        return Integer.parseInt(path.substring(1, path.length() - 1));
    }

测试差异应用

测试差异应用
测试差异应用
{
 "employee": {
  "id""1212",
  "ae86": [{
   "new""12162",
   "old""",
   "diffType""add"
  }],
  "age"34,
  "fullName": [{
   "new""John Miles111",
   "old""John Miles",
   "diffType""update"
  }],
  "contact": {
   "email""john@xyz.com",
   "phone": [{
    "new""我是改了的",
    "old""9999999999",
    "diffType""update"
   }],
   "668": [{
    "new""999999991199",
    "old""",
    "diffType""add"
   }]
  }
 }
}

差异应用代码讲解

applyDiff 方法

描述

该方法将差异应用到指定的 JSON 字符串,并返回处理后的字符串。它接受一个原始的 JSON 字符串和一个差异的 Map,通常是从 getNodesDiff 方法获取的。

方法签名

public static String applyDiff(String json, Map<String, Object> diff) throws IOException

代码解释

  • 该方法首先使用 Jackson ObjectMapper mapper 将输入的 JSON 字符串 json 解析为一个 JsonNode 对象。
  • 遍历差异的 Map 中的每个条目,每个条目表示要应用到 JSON 的变更。
  • 对于每个条目,它通过 '/' 来分割条目的键(表示 JSON 内的路径),然后按照路径迭代 JSON 结构,更新当前节点指针。
  • 如果父节点为 null 或缺失,会跳过当前迭代。
  • 根据条目的值是否为 null,它要么移除一个节点,要么更新它:
- 如果值为 null,它会从 JSON 结构中移除节点。如果父节点是数组,则移除指定索引处的元素;否则,从对象中移除指定属性。
- 如果值不为 null,它会检查值是否为数组。如果是数组,它会创建一个新的 JSON 数组节点,并根据属性是否已存在,要么替换要么添加到父节点中。如果值不是数组,则根据其类型(布尔值、数字、字符串或 JSON 对象)更新 JSON 结构中的属性。
  • 最后,它使用 mapper 将修改后的 JsonNode 转换回 JSON 字符串,并返回结果的 JSON 字符串。

getIndexFromPath 方法

描述

这是一个私有的实用方法,用于移除字符串中的方括号,并将剩余的字符串解析为整数索引。

方法签名

private static int getIndexFromPath(String path)

代码解释

  • 该方法以一个 path 字符串作为输入。
  • 它移除 path 字符串的首尾字符(假设它们是方括号),然后将剩余的子串解析为整数索引。
  • 解析后的整数索引被返回。

over
over

最后

本期结束咱们下次再见 👋~

,关注我不迷路,如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下哟~ 💗

【选题思路】

基于两串不同的 JSON 数据进行对比出来差异再将差异应用到最新的 Json 字符串当中.

【写作提纲】

一、前言

因公司业务功能当中有一个履历的功能,它有多个版本的 JSON 数据需要对比出每个版本的不同差异节点并且将差异放置在一个新的 JSON 当中原有结构不能变动,差异节点使用数组对象的形式存储,前端点击标红即可显示多个版本的节点差异数据

二、示例

介绍两个 Json 的差异对比效果

三、实现

先得到两个 Json 的差异节点集合、接着在最新的 Json 中转换 json 节点对象进行判断每个节点的字段是否符合则插入到对应的字段当中!

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/941768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android全面屏下,默认不会全屏显示,屏幕底部会留黑问题

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 公司以前的老项目&#xff0c;便出现了这种情况&#xff0c;网上搜索了各种资料&#xf…

【SpringCloudAlibaba】Sentinel使用

文章目录 概述官网解决的问题主要特性 配置下载可视化控制台POMYML 流控规则直接(默认)关联链路 降级规则降级策略实战RT异常比例异常数 热点key限流示例&#xff1a;高级选项&#xff1a;参数例外项其他 系统规则SentinelResource按资源名称限流后续处理按照Url地址限流后续处…

轻松掌控视频速度,将过快变得慢慢来!

大家好&#xff01;在观看和编辑视频时&#xff0c;有时我们会遇到速度过快的视频&#xff0c;需要进行调整以获得更佳的观赏体验或编辑效果。为了让您轻松掌控视频速度&#xff0c;我们精心研发了一款强大的工具——视频速度调整器&#xff01;让您能够将过快的视频调慢&#…

相机SD卡数据丢失如何恢复?

出门在外&#xff0c;相机是人们记录生活点滴的重要工具&#xff0c;是旅游的最佳玩伴。人们每到一个地方&#xff0c;都喜欢用相机来见证自己来过的痕迹&#xff0c;拍好的照片都会被放到相机卡里&#xff0c;但在使用相机时&#xff0c;有时我们会意外删除了重要的照片或视频…

骨传导耳机对人体有危险吗?骨传导耳机的危害有哪些

根据目前的科学研究和经验&#xff0c;骨传导耳机被认为是相对安全的使用设备&#xff0c;不会对人体造成危险。由于骨传导耳机是通过振动颅骨传递声音&#xff0c;而不是通过直接传递声音到耳朵&#xff0c;因此对耳朵和听力系统的压力较小。 骨传导耳机相反没什么危害&#x…

【已解决】Windows10 pip安装报错:UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x98

环境&#xff1a;win10, Python3.9 在Pycharm安装YoloV5的依赖包时出现报错&#xff1a;UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0x98 出现 ‘gbk’ codec can’t decode… 的报错一般是因为读取文件出现编码问题导致没法读取文件&#xff0c;因此可以在报错…

Python基础 - 构造函数

目录 基础构造函数 重写 钻石继承 super函数 基础构造函数 命名为_init_&#xff0c;在实例化对象之前会自动执行该函数 构造函数方便我们在实例化对象的时候实现个性化定制 class A():def __init__(self,x,y):self.x xself.y ydef add(self):return self.xself.yclass…

找回宝塔面板登录信息

找回宝塔面板登录信息 找回面板信息 在Xshell控制面板中输入 /etc/init.d/bt default找回登录信息 在Xshell中输入 bt之后根据提示操作 bt 之后根据提示操作![在这里插入图片描述](https://img-blog.csdnimg.cn/e209039ef4684c8a92126d5b8a0580d6.png#pic_center)

软件测试 —— Airtest的iOS实用接口介绍 (建议收藏)

1. 前言 前段时间Airtest更新了1.3.0.1版本&#xff0c;里面涉及非常多的iOS功能新增和改动&#xff0c;今天想详细跟大家聊一下里面的iOS设备接口。 PS&#xff1a;本文示例均使用本地连接的iOS设备&#xff0c;Airtest版本为1.3.0.1 。 2. 安装接口&#xff1a;install、in…

PAT 1130 Infix Expression

个人学习记录&#xff0c;代码难免不尽人意。 Given a syntax tree (binary), you are supposed to output the corresponding infix expression, with parentheses reflecting the precedences of the operators. Input Specification: Each input file contains one test ca…

煤质软化:提升采矿效率的关键技术

煤质软化&#xff1a;提升采矿效率的关键技术 随着煤炭的广泛应用和能源需求的增长&#xff0c;对煤炭采矿和利用的要求也不断提高。传统的煤炭采矿方法往往面临一些困难和挑战&#xff0c;如厚层、高硬度以及强抗压性等问题&#xff0c;导致采掘效率低下、操作困难&#xff0c…

如何搭建接口自动化测试框架?

经过了一年多的接口测试工作&#xff0c;旧的框架也做了一些新的调整&#xff0c;删除了很多冗余的功能&#xff0c;只保留了最基本的接口结构验证、接口回归测试、线上定时巡检功能。 一、框架的演进 界面 UI 做了优化&#xff0c;整个框架的画风突然不一样了&#xff08;人…

1688API技术解析,实现按图搜索1688商品(拍立淘)

一种可能的解决方案是使用图像识别和相似度匹配的算法。您可以通过将输入的图片与1688上的商品图片进行比对&#xff0c;找出最相似的商品。这涉及到图像特征提取、相似度计算以及数据库匹配等技术。您可以使用开源的图像处理库&#xff08;如OpenCV&#xff09;来进行图像处理…

38. 连续签到领金币数

文章目录 题目需求思路一实现一题目来源 题目需求 用户每天签到可以领1金币&#xff0c;并可以累计签到天数&#xff0c;连续签到的第3、7天分别可以额外领2和6金币。 每连续签到7天重新累积签到天数。 从用户登录明细表中求出每个用户金币总数&#xff0c;并按照金币总数倒…

无涯教程-分类算法 - Python实现函数

为了在Python中实现SVM&#xff0c;无涯教程将从标准库导入开始&#xff0c;如下所示- import numpy as np import matplotlib.pyplot as plt from scipy import stats import seaborn as sns; sns.set() 接下来&#xff0c;从sklearn.dataset.sample_generator创建具有线性可…

材料空间「填空解谜」:MIT 利用深度学习解决无损检测难题

内容一览&#xff1a;材料检测在工程、科学及制造业中扮演着至关重要的角色。传统的材料检测方法&#xff0c;例如切割和化学试剂检测具有破坏性&#xff0c;同时较为耗费时间和资源。近期&#xff0c;MIT 科学家利用深度学习开发了一种技术&#xff0c;能够填补缺失信息&#…

迁移学习:实现快速训练和泛化的新方法

文章目录 迁移学习的原理迁移学习的应用快速训练泛化能力提升 迁移学习的代码示例拓展应用与挑战结论 &#x1f389;欢迎来到AIGC人工智能专栏~迁移学习&#xff1a;实现快速训练和泛化的新方法 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博…

服务网格实施周期缩短 50%,丽迅物流基于阿里云 ACK 和 ASM 的云原生应用管理实践

作者&#xff1a;王夕宁、 刘强、 华相 公司介绍 丽迅物流是百丽旗下专注于时尚产业、为企业提供专业物流及供应链解决方案的服务商。其产品服务主要包括城市落地配、仓配一体、干线运输及定制化解决方案。通过自研智能化物流管理平台&#xff0c;全面助力企业合作集约化发展…

C++中前置++和后置++的详细讲解

参考链接&#xff08;链接讲的很全&#xff09;&#xff1a;C前置和后置的区别 对于迭代器和其他模板对象使用前缀形式 (i) 的自增, 自减运算符.&#xff0c;理由是 前置自增 (i) 通常要比后置自增 (i) 效率更高。 class Age { public: Age& operator() //前置 {…

c++ std::ref

ref 对于函数式编程&#xff08;如 std::bind&#xff09;&#xff0c;是对参数直接拷贝&#xff0c;而不是引用&#xff0c;std::ref的引入就是为了解决一些传参问题 ref是个函数模板&#xff0c;用来构建一个reference_wrapper对象并返回&#xff0c;该对象拥有传入的elem变…