Godot 4 源码分析 - 增加格式化字符串功能
Godot 4的主要字符串类型为String,已经设计得比较完善了,但有一个问题,格式化这块没怎么考虑。
String中有一个format函数,但这个函数只有两个参数,这咋用?
String String::format(const Variant &values, String placeholder) const {String new_string = String(this->ptr());if (values.get_type() == Variant::ARRAY) {Array values_arr = values;for (int i = 0; i < values_arr.size(); i++) {String i_as_str = String::num_int64(i);if (values_arr[i].get_type() == Variant::ARRAY) { //Array in Array structure [["name","RobotGuy"],[0,"godot"],["strength",9000.91]]Array value_arr = values_arr[i];if (value_arr.size() == 2) {Variant v_key = value_arr[0];String key = v_key;Variant v_val = value_arr[1];String val = v_val;new_string = new_string.replace(placeholder.replace("_", key), val);} else {ERR_PRINT(String("STRING.format Inner Array size != 2 ").ascii().get_data());}} else { //Array structure ["RobotGuy","Logis","rookie"]Variant v_val = values_arr[i];String val = v_val;if (placeholder.find("_") > -1) {new_string = new_string.replace(placeholder.replace("_", i_as_str), val);} else {new_string = new_string.replace_first(placeholder, val);}}}} else if (values.get_type() == Variant::DICTIONARY) {Dictionary d = values;List<Variant> keys;d.get_key_list(&keys);for (const Variant &key : keys) {new_string = new_string.replace(placeholder.replace("_", key), d[key]);}} else {ERR_PRINT(String("Invalid type: use Array or Dictionary.").ascii().get_data());}return new_string;
}
查找使用例子,都是这种效果
一看就懵。哪里有之前用的带%s %d...之类的格式化用得舒服。
动手实现一个
template <typename... Args>
static std::string str_format(const std::string &format, Args... args) {auto size_buf = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;std::unique_ptr<char[]> buf(new (std::nothrow) char[size_buf]);if (!buf)return std::string("");std::snprintf(buf.get(), size_buf, format.c_str(), args...);return std::string(buf.get(), buf.get() + size_buf - 1);
}template <typename... Args>
static String str_format(const std::u32string &format, Args... args) {auto size_buf = std::snprintf(nullptr, 0, TDrString::Convert_u32String_stdString(format).c_str(), args...) + 1;std::unique_ptr<char[]> buf(new (std::nothrow) char[size_buf]);if (!buf)return String(U"");std::string strFormat = TDrString::Convert_u32String_stdString(format);std::snprintf(buf.get(), size_buf, strFormat.c_str(), args...);std::string str(buf.get(), buf.get() + size_buf - 1);return String(str);
}
提供std::string与String两种格式化效果。之后使用方式:
cofs << U"ERROR" << str_format(U"函数 [%s] 调用失败:参数个数不匹配,形参 [%d] 个,实参 [%d]个", drFunCall.GetHint().c_str(), it->arguments.size(), drFunCall.arguments.size());
顺便再在网上转下,发现fmt库的评价不错。直接拉下来GitHub - fmtlib/fmt: A modern formatting library加入到源码中,可以使用
不过fmt的使用方式是{},有点新鲜,貌似与C++ 20兼容,那就先用上
fmt::format("[{}.Read] > 解析数据{}", prefixType, hint.utf8().ptr());
直接支持中文。
这个过程中发现一个小问题:std::string没法直接转成String,String类提供了一堆构造函数,但就是没有std::string
String(const char *p_str);String(const wchar_t *p_str);String(const char32_t *p_str);String(const char *p_str, int p_clip_to_len);String(const wchar_t *p_str, int p_clip_to_len);String(const char32_t *p_str, int p_clip_to_len);String(const StrRange &p_range);
顺手增加String与std::string互相转化的逻辑:
头文件:String(const std::string &str);operator std::string();源文件:
String::String(const std::string &str) {std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;std::wstring formatted_wstring = converter.from_bytes(str);copy_from(formatted_wstring.c_str());
} String::operator std::string() {std::string utf8;const char32_t * utf32 = ptr();for (char32_t c : utf32) {if (c <= 0x7F) {utf8.push_back(static_cast<char>(c));} else if (c <= 0x7FF) {utf8.push_back(static_cast<char>((c >> 6) | 0xC0));utf8.push_back(static_cast<char>((c & 0x3F) | 0x80));} else if (c <= 0xFFFF) {utf8.push_back(static_cast<char>((c >> 12) | 0xE0));utf8.push_back(static_cast<char>(((c >> 6) & 0x3F) | 0x80));utf8.push_back(static_cast<char>((c & 0x3F) | 0x80));} else if (c <= 0x10FFFF) {utf8.push_back(static_cast<char>((c >> 18) | 0xF0));utf8.push_back(static_cast<char>(((c >> 12) & 0x3F) | 0x80));utf8.push_back(static_cast<char>(((c >> 6) & 0x3F) | 0x80));utf8.push_back(static_cast<char>((c & 0x3F) | 0x80));} else {throw std::invalid_argument("Invalid UTF-32 character.");}}return utf8;
}
这就方便了许多。
比如,要将Variant 转为 std::string,直接一路火花带闪电
Variant v;
...
std::string str = v.operator String().operator std::string();
其实还有更简单的用法,不过在代码提示与自动完成情况下,这样写代码更为舒爽。
相关文章:

Godot 4 源码分析 - 增加格式化字符串功能
Godot 4的主要字符串类型为String,已经设计得比较完善了,但有一个问题,格式化这块没怎么考虑。 String中有一个format函数,但这个函数只有两个参数,这咋用? String String::format(const Variant &va…...

C#中XML文档与Treeview控件操作的数据同步
在前文《C#使用XML和Treeview结合实现复杂数据采集功能》中,使用Treeview展示了XML的数据,问题是如果在Treeview上进行了操作,怎样同步更改XML数据的内容呢? 这个问题看似简单,实现起来有一点小麻烦。 要实现的操作功能…...

【Java Web基础】mvn命令、Maven的安装与配置
本文极大程度上来自Maven安装(超详解),但是担心安的过程中遇到什么不一样的问题,顺便加深印象,所以还是打算自己弄一篇。 目录 第一步:Download Maven第二步:解压与安装2.1 解压2.2 安装 第一步:Download …...

加强Web应用程序安全:防止SQL注入
数据库在Web应用程序中存储和组织数据时起着至关重要的作用,它是存储用户信息、内容和其他应用程序数据的中央存储库。而数据库实现了高效的数据检索、操作和管理,使Web应用程序能够向用户提供动态和个性化的内容。然而,数据库和网络应用程序…...

【云原生】k8s中Contrainer 生命周期回调/策略/指针学习
个人主页:征服bug-CSDN博客 kubernetes专栏:kubernetes_征服bug的博客-CSDN博客 目录 1 容器生命周期 2 容器生命周期回调/事件/钩子 3 容器重启策略 4 自定义容器启动命令 5 容器探针 1 容器生命周期 Kubernetes 会跟踪 Pod 中每个容器的状态&am…...

electron+vue3全家桶+vite项目搭建【25】使用electron-updater自动更新应用
文章目录 引入实现效果实现步骤引入依赖配置electron-buidler文件封装版本升级工具类主进程调用版本更新校验渲染进程封装方法调用 测试版本更新 引入 demo项目地址 electron-updater官网 我们不可能每次发布新的版本都让用户去手动下载安装最新的包,而是应用可以…...

SQL 表别名 和 列别名
列表名 列表名之后 order by 可以用别名 也可以用原名, where 中不能用别名的 SQL语句执行顺序: from–>where–>group by -->having — >select --> order 第一步:from语句,选择要操作的表。 第二步࿱…...

面试之快速学习c++11-函数模版的默认模版参数,可变模版,tuple
//学习地址: http://c.biancheng.net/view/3730.html 函数模版的默认模版参数 在 C98/03 标准中,类模板可以有默认的模板参数,如下: template <typename T, typename U int, U N 0> struct TestTemplateStruct {};但是…...

Visual Studio Code 常见的配置、常用好用插件以及【vsCode 开发相应项目推荐安装的插件】
一、VsCode 常见的配置 1、取消更新 把插件的更新也一起取消了 2、设置编码为utf-8:默认就是了,不用设置了 3、设置常用的开发字体:Consolas, 默认就是了,不用设置了 字体对开发也很重要,不同字体,字母形…...

源码编译安装gcc
摘要: 在编译开源的FunASR项目的C代码时,可能要求的gcc版本不符合,需要升级gcc版本,但是从网上搜索升级gcc方式,大部分都是通过简单的yum命令方式升级,我也尝试了这个方式,这种方式并不能升级到…...

pc文件上传
1.代码: <template><div><el-upload:multiple"true":auto-upload"true":headers"headers":action"uploadFileUrl":before-upload"handleBeforeUpload":on-error"handleUploadError":o…...

Vue3_对响应式对象解构赋值之后失去响应性
官网toRefs() :响应式 API:工具函数 | Vue.js toRefs 在调用时只会为源对象上可以枚举的属性创建 ref。如果要为可能还不存在的属性创建 ref,请改用 toRef。 setup(){const state reactive({name:"张三"age:14})const stateAsToRefs toRef…...

3d 地球与卫星绕地飞行
1 创建场景 2 创建相机 3 创建地球模型 4 创建卫星中心 5 创建卫星圆环及卫星 6 创建控制器 7 创建渲染器 <template><div class"home3dMap" id"home3dMap"></div> </template><script> import * as THREE from three impo…...

Opencv-C++笔记 (16) : 几何变换 (图像的翻转(镜像),平移,旋转,仿射,透视变换)
文章目录 一、图像平移二、图像旋转2.1 求旋转矩阵2.2 求旋转后图像的尺寸2.3手工实现图像旋转2.4 opencv函数实现图像旋转 三、图像翻转3.1左右翻转3.2、上下翻转3.3 上下颠倒,左右相反 4、错切变换4.1 实现错切变换 5、仿射变换5.1 求解仿射变换5.2 OpenCV实现仿射…...

第十次CCF计算机软件能力认证
第一题:分蛋糕 小明今天生日,他有 n 块蛋糕要分给朋友们吃,这 n 块蛋糕(编号为 1 到 n)的重量分别为 a1,a2,…,an。 小明想分给每个朋友至少重量为 k 的蛋糕。 小明的朋友们已经排好队准备领蛋糕,对于每个朋…...

【敏捷开发】测试驱动开发(TDD)
测试驱动开发(Test-Driven Development,简称TDD)是敏捷开发模式中的一项核心实践和技术,也是一种设计方法论。TDD有别于以往的“先编码,后测试”的开发模式,要求在设计与编码之前,先编写测试脚本…...

骑砍二 ATC MOD 使用教程与应用案例解析
骑砍二 ATC MOD 使用教程与应用案例解析 作者:blibli-财不外漏 / NEXUSMODS-PuepleKarmen 案例MOD依赖:ATC - Adonnay’s Troop Changer & AEW - Adonnay’s Exotic Weaponry & New Armor 文本编辑工具:VS Code(推荐使用&…...

python和c语言哪个好上手,c语言和python语言哪个难
大家好,本文将围绕python和c语言哪个更值得学展开说明,python语言和c语言哪个简单是一个很多人都想弄明白的事情,想搞清楚c语言和python语言哪个难需要先了解以下几个事情。 前言 新手最容易拿来讨论的三个语言,具体哪个好&#x…...

智能优化算法 | Matlab实现鲸鱼优化算法(Whale Optimization Algorithm)(内含完整源码)
文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现鲸鱼优化算法(Whale Optimization Algorithm)(内含完整源码) 研究内容 步骤 1:设置鲸鱼数量 N 和算法的最大迭代次数 tmax,初始化位置信息; 步骤 2:计算每条鲸鱼的适应度,…...

Android随笔-VPN判断
Android中判断当前网络是否为VPN /*** 判断当前网络是否为VPN* param context* return*/public static boolean hasVPN(Context context) {// 查询网络状态,被动监听网络状态变化ConnectivityManager cm (ConnectivityManager) context.getSystemService(Context.C…...

【黑马头条之kafka及异步通知文章上下架】
本笔记内容为黑马头条项目的kafka及异步通知文章上下架部分 目录 一、kafka概述 二、kafka安装配置 三、kafka入门 四、kafka高可用设计 1、集群 2、备份机制(Replication) 五、kafka生产者详解 1、发送类型 2、参数详解 六、kafka消费者详解 1、消费者…...

Modelsim打开后报unable to checkout a viewer license
找到Modelsim安装包中的MentorKG.exe文件和patch64_dll.bat文件,将这两个文件拷贝到Modelsim安装目录中的win64文件夹: 在win64文件夹中找到mgls64.dll,将它拷贝粘贴一份后修改名字为mgls.dll: 双击win64文件夹中的patch64_dll.ba…...

计算机视觉与图形学-神经渲染专题-Seal-3D(基于NeRF的像素级交互式编辑)
摘要 随着隐式神经表示或神经辐射场 (NeRF) 的流行,迫切需要与隐式 3D 模型交互的编辑方法,以完成后处理重建场景和 3D 内容创建等任务。虽然之前的作品从不同角度探索了 NeRF 编辑,但它们在编辑灵活性、质量和速度方面受到限制,无…...

synchronized的底层实现原理
技术主题 synchronized 是 Java 中用于实现线程同步的关键字。它的底层原理涉及到对象头、Monitor(监视器)和内存屏障等概念。 技术原理 技术一:对象头 对象头:每个 Java 对象在内存中都有一个对象头,用于存储对象的元数据信息,比如对象的哈希码、GC 信息以及锁状态等…...

屏幕取色器Mac版_苹果屏幕取色工具_屏幕取色器工具
Sip for Mac 是Mac系统平台上的一款老牌的颜色拾取工具,是设计师和前端开发工作者必不可少的屏幕取色软件,你只需要用鼠标点一下即可轻松地对屏幕上的任何颜色进行采样和编码,并将颜色数据自动存到剪切板,方便随时粘贴出来。 Sip…...

HDFS中的Federation联邦机制
HDFS中的Federation联邦机制 当前HDFS体系架构--简介局限性 联邦Federation架构简介好处配置示例 当前HDFS体系架构–简介 当前的HDFS结构有两个主要的层: 命名空间(namespace) 由文件,块和目录组成的统一抽象的目录树结构。由n…...

Spring Boot 单元测试
目录 1.什么是单元测试? 2.单元测试的优点 3.Spring Boot 单元测试使用 3.1 生成单元测试的类 3.2 添加 Spring Boot 框架测试注解:SpringBootTest 3.3 添加单元测试业务逻辑 3.4 注解 Transactional 4. 断言 1.什么是单元测试? 单元…...

k8s部署nginx访问Tomcat
1.nginx打包镜像 #1、编写DockerFilemkdir /opt/my_nginx_dockerfilecd /opt/my_nginx_dockerfile cat >default.conf<<EOF server {listen 80;listen [::]:80;server_name localhost;#access_log /var/log/nginx/host.access.log main;location / {root …...

springboot配置文件的使用
目录 1.application.properties是springboot默认的配置文件,但是比较繁琐,一般用.yml文件 2. 配置文件的作用 3.配置文件的使用 1.application.properties是springboot默认的配置文件,但是比较繁琐,一般用.yml文件 ①、properti…...

blender 毛发粒子
新建平面,点击右侧粒子系统,选择毛发,调整毛发长度,数量(Number),调整数量是为了避免电脑卡顿; 上面设置的每一根柱子都可以变成一个物体,点击渲染,渲染为选择…...