JSON数据格式解析库(cJSON、Jansson)的使用&在STM32上移植和使用

2023-11-04

json | json-c使用入门 这篇讲的也不错,抽空看下(网络传输json数据)
https://www.bilibili.com/video/av669454528?p=3&spm_id_from=pageDriver

轻量级C语言JSON解析库

参考博文:cJSON使用详细教程 | 一个轻量级C语言JSON解析器
作者:Mculover666
地址:https://mculover666.blog.csdn.net/article/details/103796256?spm=1001.2014.3001.5502

1.JSON与cJSON

JSON —— 轻量级的数据格式

JSON 全称 JavaScript Object Notation,即 JS对象简谱,是一种轻量级的数据格式。

它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

JSON语法规则

JSON对象是一个无序的"名称/值"键值对的集合:

  • 以"{“开始,以”}"结束,允许嵌套使用,即对象里面嵌套对象;
  • 每个名称和值成对出现(名称又叫做键,所以又叫键值对),名称和值之间使用":"分隔;
  • 键值对之间用","分隔
  • 在这些字符前后允许存在无意义的空白符;

对于键值,可以有如下值:

  • 一个新的json对象
  • 数组:使用"[“和”]"表示
  • 数字:直接表示,可以是整数,也可以是浮点数
  • 字符串:使用引号"表示
  • 字面值:false、null、true中的一个(必须是小写)

注意:
在这里插入图片描述
详细的JSON数据格式参照:太极创客JSON基础

示例如下:

{
    "name": "mculover666",
    "age": 22,
    "weight": 55.5,
    "address":
    {		//值是一个对象,即对象里面嵌套对象
        "country": "China",
        "zip-code": 111111
    },
    "skill": ["c", "Java", "Python"],//数组
    "student": false				 //布尔
}

cJSON

cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。

cJSON项目托管在Github上,仓库地址如下:

https://github.com/DaveGamble/cJSON

使用Git命令将其拉取到本地:

git clone https://github.com/DaveGamble/cJSON.git

从Github拉取cJSON源码后,文件非常多,但是其中cJSON的源码文件只有两个:

  • cJSON.h
  • cJSON.c

使用的时候,只需要将这两个文件复制到工程目录,然后包含头文件cJSON.h即可,如下:

#include "cJSON.h"

2.cJSON数据结构和设计思想

cJSON的设计思想从其数据结构上就能反映出来。

cJSON使用cJSON结构体来表示一个JSON数据,定义在cJSON.h中,源码如下:

/* The cJSON structure: */
typedef struct cJSON
{
    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *next;
    struct cJSON *prev;
    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    struct cJSON *child;

    /* The type of the item, as above. */
    int type;

    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    /* The item's number, if type==cJSON_Number */
    double valuedouble;

    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    char *string;
} cJSON;

cJSON的设计很巧妙。

首先,它不是将一整段JSON数据抽象出来,而是将其中的一条JSON数据抽象出来,也就是一个键值对,用上面的结构体 strcut cJSON 来表示,其中用来存放值的成员列表如下:

  • String:用于表示该键值对的名称
  • type:用于表示该键值对中值的类型
  • valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
  • valueint:如果键值类型(type)是整数,则将该指针指向键值;
  • valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;

其次,一段完整的JSON数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段JSON数据,如上面的代码所示:

  • next指针:指向下一个键值对
  • prev指针:指向上一个键值对

最后,因为JSON数据支持嵌套,所以一个键值对的值会是一个新的JSON数据对象(一条新的链表),也有可能是一个数组,方便起见,在cJSON中,数组也表示为一个数组对象,用链表存储,所以:

在键值对结构体中,当该键值对的值是一个嵌套的JSON数据或者一个数组时,由child指针指向该条新链表。

3.JSON数据封装

封装方法

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。

首先来讲述一下链表中的一些术语:

  • 头指针:指向链表头结点的指针;
  • 头结点:不存放有效数据,方便链表操作;
  • 首节点:第一个存放有效数据的节点;
  • 尾节点:最后一个存放有效数据的节点;

明白了这几个概念之后,我们开始讲述创建一段完整的JSON数据,即如何创建一条完整的链表。

① 创建头指针:

 cJSON* cjson_test = NULL;

② 创建头结点,并将头指针指向头结点:

cjson_test = cJSON_CreateObject();

③ 尽情的向链表中添加节点:

cJSON_AddNullToObject(cJSON * const object, const char * const name);

cJSON_AddTrueToObject(cJSON * const object, const char * const name);

cJSON_AddFalseToObject(cJSON * const object, const char * const name);

cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

cJSON_AddObjectToObject(cJSON * const object, const char * const name);

cJSON_AddArrayToObject(cJSON * const object, const char * const name);

输出JSON数据

上面讲述,一段完整的JSON数据就是一条长长的链表,那么,如何打印出这段JSON数据呢?

cJSON提供了一个API,可以将整条链表中存放的JSON信息输出到一个字符串中:

(char *) cJSON_Print(const cJSON *item);

使用的时候,只需要接收该函数返回的指针地址即可。

封装数据和打印数据示例

单纯的讲述方法还不够,下面用一个例子来说明,封装出开头给出的那段JSON数据:

#include <stdio.h>
#include "cJSON.h"

int main(void)
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_skill = NULL;
    char* str = NULL;

    /* 创建一个JSON数据对象(链表头结点) */
    cjson_test = cJSON_CreateObject();

    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddStringToObject(cjson_test, "name", "mculover666");

    /* 添加一条整数类型的JSON数据(添加一个链表节点) */
    cJSON_AddNumberToObject(cjson_test, "age", 22);

    /* 添加一条浮点类型的JSON数据(添加一个链表节点) */
    cJSON_AddNumberToObject(cjson_test, "weight", 55.5);

    /* 添加一个嵌套的JSON数据(添加一个链表节点) */
    cjson_address = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_address, "country", "China");
    cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);
    cJSON_AddItemToObject(cjson_test, "address", cjson_address);

    /* 添加一个数组类型的JSON数据(添加一个链表节点) */
    cjson_skill = cJSON_CreateArray();
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));
    cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);

    /* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */
    cJSON_AddFalseToObject(cjson_test, "student");

    /* 打印JSON对象(整条链表)的所有数据 */
    str = cJSON_Print(cjson_test);
    printf("%s\n", str);

    return 0;
}

编译运行:

gcc cJSON.c example1.c -o example1

实验结果如图:
在这里插入图片描述

该JSON数据链表的关系如图:
在这里插入图片描述

4.cJSON数据解析

解析方法

解析JSON数据的过程,其实就是剥离一个一个链表节点(键值对)的过程。

解析方法如下:

① 创建链表头指针:

cJSON* cjson_test = NULL;

② 解析整段JSON数据,并将链表头结点地址返回,赋值给头指针:
解析整段数据使用的API只有一个:

(cJSON *) cJSON_Parse(const char *value);

③ 根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址

(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

④ 如果JSON数据的值是数组,使用下面的两个API提取数据:

(int) cJSON_GetArraySize(const cJSON *array);
(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);

解析示例

下面用一个例子来说明如何解析出开头给出的那段JSON数据:

#include <stdio.h>
#include "cJSON.h"

char *message = //json格式数据,需要显示引号,都需要用\转义
"{                              \
    \"name\":\"mculover666\",   \
    \"age\": 22,                \
    \"weight\": 55.5,           \
    \"address\":                \
        {                       \
            \"country\": \"China\",\
            \"zip-code\": 111111\
        },                      \
    \"skill\": [\"c\", \"Java\", \"Python\"],\
    \"student\": false          \
}";

int main(void)
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_name = NULL;
    cJSON* cjson_age = NULL;
    cJSON* cjson_weight = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_address_country = NULL;
    cJSON* cjson_address_zipcode = NULL;
    cJSON* cjson_skill = NULL;
    cJSON* cjson_student = NULL;
    int    skill_array_size = 0, i = 0;
    cJSON* cjson_skill_item = NULL;

    /* 解析整段JSO数据 */
    cjson_test = cJSON_Parse(message);
    if(cjson_test == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    /* 依次根据名称提取JSON数据(键值对) */
    cjson_name = cJSON_GetObjectItem(cjson_test, "name");
    cjson_age = cJSON_GetObjectItem(cjson_test, "age");
    cjson_weight = cJSON_GetObjectItem(cjson_test, "weight");

    printf("name: %s\n", cjson_name->valuestring);
    printf("age:%d\n", cjson_age->valueint);
    printf("weight:%.1f\n", cjson_weight->valuedouble);

    /* 解析嵌套json数据 */
    cjson_address = cJSON_GetObjectItem(cjson_test, "address");
    cjson_address_country = cJSON_GetObjectItem(cjson_address, "country");
    cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code");
    printf("address-country:%s\naddress-zipcode:%d\n", cjson_address_country->valuestring, cjson_address_zipcode->valueint);

    /* 解析数组 */
    cjson_skill = cJSON_GetObjectItem(cjson_test, "skill");
    skill_array_size = cJSON_GetArraySize(cjson_skill);
    printf("skill:[");
    for(i = 0; i < skill_array_size; i++)
    {
        cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);
        printf("%s,", cjson_skill_item->valuestring);
    }
    printf("\b]\n");

    /* 解析布尔型数据 */
    cjson_student = cJSON_GetObjectItem(cjson_test, "student");
    if(cjson_student->valueint == 0)
    {
        printf("student: false\n");
    }
    else
    {
        printf("student:error\n");
    }
    
    return 0;
}

编译:

gcc cJSON.c example2.c -o example2

运行结果如图:
在这里插入图片描述

注意事项

在本示例中,因为我提前知道数据的类型,比如字符型或者浮点型,所以我直接使用指针指向对应的数据域提取,在实际使用时,如果提前不确定数据类型,应该先判断type的值,确定数据类型,再从对应的数据域中提取数据。

5.cJSON使用过程中的内存问题

内存及时释放

cJSON的所有操作都是基于链表的,所以cJSON在使用过程中大量的使用malloc从堆中分配动态内存的,所以在使用完之后,应当及时调用下面的函数,清空cJSON指针所指向的内存,该函数也可用于删除某一条数据:

(void) cJSON_Delete(cJSON *item);

注意:该函数删除一条JSON数据时,如果有嵌套,会连带删除。

内存钩子

cJSON在支持自定义malloc函数和free函数,方法如下:

① 使用cJSON_Hooks来连接自定义malloc函数和free函数:

typedef struct cJSON_Hooks
{
      /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
      void *(CJSON_CDECL *malloc_fn)(size_t sz);
      void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;

② 初始化钩子cJSON_Hooks

(void) cJSON_InitHooks(cJSON_Hooks* hooks);

cJSON在STM32移植和使用

参照:物联网项目设计(四)cJSON 在 STM32 移植和使用
作者:张竞豪
地址:https://blog.csdn.net/weixin_42487906/article/details/104542529

概要

JSON格式是互联网通讯过程中常用的格式。包括MQTT协议也不例外,MQTT协议的数据收发都是使用JSON格式完成的。在使用MQTT协议进行通讯之前,我们需要掌握在c语言环境下JSON格式数据的操作。对JSON数据的操作我们使用了cJSON开源库。在使用的过程中,也遇到了不少问题(见后文),为此我查阅了很多资料,最后找到比较简单的方法解决了这个问题。

本篇介绍如何生成cJSON格式数据,并转化成字符串,通过串口发送到上位机。

硬件准备

使用STM32主控的开发板或相关硬件设备

软件准备

上位机串口助手

实际操作步骤

1.使用CubeMx建立一个简单的工程,只需要配置串口,但一定要注意,配置堆栈大小的时候一定要配置的大一点,因为cJSON分配内存的时候会占用不少内存空间,内存分配是单片机移植cJSON遇到的最常见的问题,如果内存分配的不对,很容易就导致生成的JSON字符串里面什么都没有。网上很多解决方案是自行编写内存管理函数,也就是malloc和free,这种方法太麻烦而且可移植性不高,最后我选择了使用增大堆栈的方式。
在这里插入图片描述
2.从github上获取cJSON的源码并解压,如下图
在这里插入图片描述
我们只需要其中的cJSON.c和cJSON.h,并把他们复制到工程中。
在这里插入图片描述
3.实际编写代码部分,我们需要生成一个JSON格式的字符串如下

{
	"name":	"Alpha",
	"address":	{
		"conutry":	"China",
		"city":	"Luoyang"
	},
	"info":	{
		"age":	21,
		"weight":	66
	}
}

实际编写代码部分,我们要注意的是,在使用cJSON之后,要及时将其删除,其中删除父对象也会自动迭代删除子对象

下面是初始化部分,完成生成JSON格式数据,并将其转化为字符串格式数据,最后删除


	char *buffer;
	cJSON* cjson_test = NULL;
	cJSON* cjson_address = NULL;
	cJSON* cjson_info = NULL;
	
	
	cjson_test = cJSON_CreateObject();
	//
	//
	
	cJSON_AddStringToObject(cjson_test,"name","Alpha");
	
	cjson_address = cJSON_CreateObject();
	cJSON_AddStringToObject(cjson_address,"conutry","China");
	cJSON_AddStringToObject(cjson_address,"city","Luoyang");
	
	cJSON_AddItemToObject(cjson_test,"address",cjson_address);
	
	cjson_info = cJSON_CreateObject();
	cJSON_AddNumberToObject(cjson_info,"age",21);
	cJSON_AddNumberToObject(cjson_info,"weight",66);
	
	cJSON_AddItemToObject(cjson_test,"info",cjson_info);
	
	buffer = cJSON_Print(cjson_test);
	
	cJSON_Delete(cjson_test);

下面是发送字符串到上位机部分

/* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_Delay(1000);
	  u1_printf("You Json Is:%s\r\n",buffer);
  }
  /* USER CODE END 3 */
}

4,编译代码并在上位机中观察现象在这里插入图片描述
完成了所需要的功能

总结

本部分内容完成了cJSON的移植和JSON格式的初步使用,下一阶段准备使用paho 的开源mqtt库链接百度云天工,并且使用paho自带的ping函数,完成stm32链接百度云天工后的连接检测。

快速生成JSON数据(sprintf)和解析JSON数据(strstr)技巧

参照:骚操作!快速创建JSON数据和解析JSON数据
作者:Mculover666
地址:https://mculover666.blog.csdn.net/article/details/103794279?spm=1001.2014.3001.5502

乐鑫云平台在对接的时候,可以使用tcp socket发送和接收json数据进行交互,之前专门写了一篇文章讲述cJSON的使用,然而,看了乐鑫给的官方代码后,我只能说,突如其来的骚,闪了**的腰!

1. 生成JSON数据

核心思想:构造字符串!

这里我拿设备激活举个例子,设备激活的数据格式如下:

{"path": "/v1/device/activate/", "method": "POST", "meta": {"Authorization": "token HERE_IS_THE_MASTER_DEVICE_KEY"}, "body": {"encrypt_method": "PLAIN", "bssid": ":bssid", "token": ":token"}}

其中:

  • HERE_IS_THE_MASTER_DEVICE_KEY:填写之前获取的秘钥;
  • bssid:填写设备MAC地址;
  • token :随机值即可,可以留空;

这样的一条数据,如果使用cJSON的函数一条一条创建,不仅代码量大,而且内存占用量也极大,接下来向大家介绍一个骚操作,看完后,我相信你会点赞的!

首先直接使用宏定义将整段JSON字符串给出:

#define ACTIVE_DATA                  \
"{\n\"path\": \"/v1/device/activate/\",\n\
\"method\": \"POST\",\n\
\"meta\":\
{\"Authorization\": \"token %s\"},\n\
\"body\":\
{\"encrypt_method\": \"PLAIN\",\
\"bssid\": \"%s\",\
\"token\": \":\"}\n}\n"

然后一行命令即可构造出将其中两个需要用户给出的值定义:

#define TOKEN   "ef97b306620d5e9de19d7b2131742b152b2e94d0"
#define BSSID   "dc:4f:22:5e:90:b7"

最后一行代码解决问题,简洁到爆炸:使用拼接函数

sprintf(active_data, ACTIVE_DATA, TOKEN, BSSID);

整段程序如下:

#include <stdio.h>
#include <stdlib.h>

#define ACTIVE_DATA                  \
"{\n\"path\": \"/v1/device/activate/\",\n\
\"method\": \"POST\",\n\
\"meta\":\
{\"Authorization\": \"token %s\"},\n\
\"body\":\
{\"encrypt_method\": \"PLAIN\",\
\"bssid\": \"%s\",\
\"token\": \":\"}\n}\n"

#define TOKEN   "ef97b306620d5e9de19d7b2131742b152b2e94d0"
#define BSSID   "dc:4f:22:5e:90:b7"

int main(void)
{
    char* active_data = malloc(300);
    sprintf(active_data, ACTIVE_DATA, TOKEN, BSSID);
    printf(active_data);
    return 0;
}

编译运行:
在这里插入图片描述

2. 解析JSON数据

"deliver_to_device": true, "get": "action": "LED_ON", "meta": "Authorization": "token 8668c64f40d172be31eb4f12cbcaf4e57c9e1e3c", "Time-Zone": "Asia/Shanghai", "method": "GET", "nonce": 587250592, "path": "/v1/device/rpc/"

其中想要的数据只有:
在这里插入图片描述
所以,为什么要浪费精力,浪费代码,浪费内存去用cJSON一条一条解析数据,而且解析出来有用的值只有“LED_ON”,所以直接使用C库函数strstr()判断这段字符串中有没有“LED_ON”就ok啦~

#include <stdio.h>
#include <string.h>

char rpc_cmd[] = "\
\"deliver_to_device\": true,\
\"get\": \"action\": \"LED_ON\",\
\"meta\": \"Authorization\": \"token 8668c64f40d172be31eb4f12cbcaf4e57c9e1e3c\",\
\"Time-Zone\": \"Asia/Shanghai\",\
\"method\": \"GET\",\
\"nonce\": 587250592,\
\"path\": \"/v1/device/rpc/\"\
";

int main(void)
{
    if(strstr(rpc_cmd, "LED_ON"))
    {
        printf("LED need to turn on!\n");
    }
    return 0;
}

编译运行:
在这里插入图片描述

Keil环境下Jansson解析库的使用

摘自:Keil环境下Jansson解析库的使用——基于STM32F103
地址:https://blog.csdn.net/whik1194/article/details/106872260
摘自:Keil环境下使用Jansson构建JSON——基于STM32F103
地址:https://blog.csdn.net/whik1194/article/details/108596840?spm=1001.2014.3001.5502

对于嵌入式开发,比较常用的就是cJSON解析库了,但是使用这个库对内存开销比较大,需要大量使用malloc和free进行动态内存分配和释放。对于单片机这种资源短缺的芯片来说,简直是太吃力了。使用STM32等单片机,不能解析多层JSON时,还需要调大堆栈。

今天来了解一下一个和cJSON非常类似的解析库——Jansson的使用,支持解析和构建JSON字符串,不需要动态分配内存,使用方法和cJSON几乎一样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JSON数据格式解析库(cJSON、Jansson)的使用&在STM32上移植和使用 的相关文章

随机推荐

  • 在线小说阅读网站开源项目地址整合

    项目开源地址 1 https github com ShanaMaid oho reader 小说数据接口地址 1 http api zhuishushenqi com book 50865988d7a545903b000009 留言评论样
  • Vue3【1.v-if 和 v-show 、2.动态组件、 3.网页的渲染 、4.v-for】

    文章目录 1 v if 和 v show 2 动态组件 3 网页的渲染 4 v for 4 1 v for 与对象 4 2 在 v for 里使用范围值 4 3 v for 与 v if 4 4 通过 key 管理状态 4 5 组件上使用
  • Android APP OpenGL ES应用(01)GLSurfaceView 2D/3D绘图基础

    1 Android 3D图形基础简介 1 1 OpenGL ES简介 OpenGL本身是开放图形库的一种标准 定义了一个跨语言 跨平台的编程规范 主要用于3D图形编程 OpenGLES是OpenGL的裁剪版本 主要是针对嵌入式设备 移动设备
  • layui 传递前端请求_基于Layui的页面传参及获取参数

    预计实现效果 通过点击编辑按钮 能够把该行数据显示在表格中 table html页面所属表格截取一行 edit html页面 实现代码 table html关键代码 传递参数 监听更新 编辑 操作 table on tool current
  • zookeeper集群扩容/下线节点实践

    环境 zookeeper版本 3 4 6 jdk版本 1 7 0 80 10 111 1 29 zk1 10 111 1 44 zk2 10 111 1 45 zk3 10 111 1 46 zk4 10 111 1 47 zk5 一 zo
  • python输出带有颜色的内容

    20200816 主要参考了文章 1 不使用第三方库 我当时的需求只需要将字体变色 比如输出 Error 其中Error为红色 def error print output print 033 31mError 033 0m output
  • strstr(str1,str2)函数使用 出现问题解析

    定义 strstr str1 str2 函数用于判断字符串str2是否是str1的子串 如果是 则该函数返回str2在str1中首次出现的地址 否则 返回NULL 定义说的有点羞涩难懂 举个例子就知道了 比如 char str2 cdef
  • 学习率与batch-size大小的关系

    近日训练的电脑从一个显卡升级到了4张显卡 这就意味着能够更快的训练速度 但是实际中 并不是这样的 多卡意味着可以使用大点的batch size 这样子会导致每个epoch收敛的更慢了 虽然说速度变快了 但是更新次数变少了 所以收敛的更慢了
  • Java正则表达式Pattern和Matcher

    Java字符串支持使用正则表达式进行替换和分隔操作 字符串提供的正则表达式操作是有限的 比如打印正则表达式匹配到的每一个字符串就无法通过字符串提供的方法来实现 Java使用Pattern和Matcher两个类来支持正则表达式功能 字符串提供
  • java:错误: 找不到符号

    我写了这样一个代码 class Demo public static void main String args int arr 3 5 1 7 2 3 5 6 6 1 8 2 int sum 0 for int x 0 x
  • Llama 2|Meta开源语言模型

    此次 Meta 发布的 Llama 2 模型系列包含 70 亿 130 亿和 700 亿三种参数变体 此外还训练了 340 亿参数变体 但并没有发布 只在技术报告中提到了 据介绍 相比于 Llama 1 Llama 2 的训练数据多了 40
  • 应用层--DNS

    目录 2 4 DNS 域名系统 2 4 1 域名 域名的层级分类 域名的构成 域名管理 2 4 2 域名服务器 DNS 根名字服务器 权威服务器 TLD服务器 本地名字服务器 Local Name Server 名字服务器 Name Ser
  • mysql全局自动提交,MySQL自动提交

    在MySQL中 如果不更改其自动提交变量 则系统会自动向数据库提交结果 用户在执行数据库操作过程中 不需要使用START TRANSACTION语句开始事务 应用COMMIT或者ROLLBACK提交事务或执行回滚操作 如果用户希望通过控制M
  • 绿色经营:从优秀到卓越最显性准则

    关注 实在的力量 郑崇华与台达电的经营智慧 一书 是受 绿色企业家 的启发 绿色企业家 是美国绿色企业标杆英特飞公司的创始人雷C 安德森的自传体管理专著 联想到 从绿到金 等书 我们知道许多美国企业已经从绿色经营中实实在在获利并走上健康的发
  • Unity3D启动时卡在项目Loading界面的解决方法

    问题描述 打开U3D的时候 U3D一直卡在项目选择的界面上 一直显示 Loading 关闭重新开也不行 可能原因 项目配置发生错误 导致无法读取 一直卡Loading 解决方案 1 找到最近一次操作U3D时所加载的项目 一般大概率是这个 如
  • 数字化转型必备:数睿通 2.0 数据中台升级详解

    引言 转眼又过了一个月的时间 数睿通 2 0 数据中台也迎来了本月的更新 本次更新主要包括 数据资产完善 资源评价 数据集市完善 打通审批流程 修复数据生产由于 Druid SQLUtils 不支持 Doris 导致无法建表的问题 优化贴源
  • element-plus dialog #header无效

    这是官方文档的一个坑 来看下官方的案例 他这里使用的是 header来标记title插槽 正确应该是 title 而官网案例打开后也是看不到的自定义的标题内容的 标题这一栏是空白的 而看文档说明也是叫使用的header 这里下面还标注了ti
  • 神秘AI换脸软件入侵全球社交网络!马斯克秒变文艺复兴贵族

    人工智能学习离不开实践的验证 推荐大家可以多在FlyAI AI竞赛服务平台多参加训练和竞赛 以此来提升自己的能力 FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台 每周免费提供项目开源算法样例 支持算法能力变现以及快
  • Vue3中自定义指令监听元素尺寸变化

    vue对元素的宽高变化看了一下 基本都是用的定时器解决的 刚好看到JS的一个属性方法 可以专门监测元素的尺寸变化 MDN地址 https developer mozilla org zh CN docs Web API ResizeObse
  • JSON数据格式解析库(cJSON、Jansson)的使用&在STM32上移植和使用

    json json c使用入门 这篇讲的也不错 抽空看下 网络传输json数据 https www bilibili com video av669454528 p 3 spm id from pageDriver 目录 轻量级C语言JSO