奇牛Qt05 Qt字符串QString —— 奇牛+gemini

奇牛Qt05 Qt字符串QString —— 奇牛+gemini

1. 核心概述

  • 头文件#include <QString>
  • 模块QT += core
  • 基本功能:Qt 框架中用于处理文本的通用字符串类型。它的使用方式与标准库的 std::string 非常相似,但在底层设计和字符编码上有所不同。

1.1 QString 与 std::string 的区别

  1. 字符编码QString 内部的每个字符都是 QChar 类型(16位,使用 UTF-16 编码),对多语言(如中文)支持极佳;而 std::string 存储的是 char 类型(8位,通常使用 UTF-8 编码)。
  2. 内存机制(隐式共享 / 写时复制)QString 内部实现了隐式共享(Copy-on-Write),以减少内存开销并避免不必要的数据深拷贝。Qt 的许多其他类(如 QByteArray, QBrush, QDir, QBitmap 等)也都采用了这一机制。

写时复制原理详解

QString str1 = "nameless"; // 初始化
QString str2 = str1;   // 拷贝构造(浅拷贝)
// 此时 str1 和 str2 指向同一个底层数据结构。该结构包含字符串内容和“引用计数器”。此时计数器值为 2。

str2[2] = 'a'; 
// 发生修改!触发“深拷贝”。str2 会指向一个全新克隆的数据结构(计数器为 1),
// 同时 str1 指向的原结构计数器减为 1。在此新结构上完成修改。

str2[2] = 'm'; 
// 再次修改 str2。由于此时 str2 的数据结构没有被共享(计数器为 1),因此不会发生任何拷贝动作。

str1 = str2; 
// str1 放弃原结构(原结构计数器变为 0,内存被自动释放)。
// 随后 str1 重新指向 str2 的结构,该结构的引用计数再次变为 2。

2. 常用 API 详解与使用格式

2.1 初始化与打印

语法格式:支持赋值、构造函数、拷贝构造等多种初始化方式。

示例代码

QString str1 = "nameless";
QString str2 = str1;
QString str3("nameless");
QString str4(str1);
qDebug() << str1 << str2 << str3 << str4;

2.2 判空

函数原型bool isEmpty() const;

讲解:当字符串长度为 0(即没有字符,如 "" 或未初始化的默认对象)时返回 true,否则返回 false

示例代码

QString str1;       // 未初始化,isEmpty() 为 true
QString str2 = "";  // 空串,isEmpty() 为 true
QString str3 = " "; // 包含一个空格,isEmpty() 为 false

2.3 获取字符串长度

函数原型

  • int size() const;
  • int length() const;
  • int count() const;

讲解:这三个方法在 QString完全等效,皆返回字符串中的字符个数。一个汉字在 QString 中被计为一个字符(一单位长度/QChar)。

示例代码

QString str1 = "nameless";
qDebug() << str1.size() << str1.length() << str1.count();
// 输出:8 8 8

2.4 添加与插入数据

函数原型

  • 尾部追加:QString& append(const QString &str);(或使用重载运算符 +=
  • 任意位置插入:QString& insert(int position, const QString &str);

讲解insert() 的第一个参数为插入的索引位置。若传入的索引值超过当前字符串最大长度,内部会自动补充空格;若索引为负数,则插入失败,不产生任何效果。

示例代码

// 1. 尾部追加
QString str1 = "你是谁啊?";
str1 += "我是";
str1.append("nameless");
qDebug() << str1; // "你是谁啊?我是nameless"

// 2. 任意位置插入
QString str2 = "你是谁啊?咕咕嘎嘎!";
str2.insert(5, "我");
str2.insert(6, "是凑企鹅!");
qDebug() << str2; // "你是谁啊?我是凑企鹅!咕咕嘎嘎!"

// 3. .insert索引值过大补空格;索引为负插入失败,无效果
QString str3 = "你是谁啊?";
str3.insert(15, "我是香企鹅!");
str3.insert(-1, "咕咕嘎嘎!");
qDebug() << str3; // "你是谁啊?          我是香企鹅!"

2.5 替换字符串

函数原型QString& replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);

讲解:将字符串中所有出现的 before 子串替换为 after。第三个参数控制是否区分大小写:

  • Qt::CaseSensitive(默认):区分大小写。
  • Qt::CaseInsensitive:不区分大小写。

示例代码

QString str1 = "A! a! o!";
QString str2 = "你是谁啊?我是nameless";

// 默认区分大小写
str1.replace("A", "欸");
qDebug() << str1; //"欸! a! o!"

// 传入 Qt::CaseInSensitive, 替换时不缺分大小写
str2.replace("NAMELESS", "凑企鹅", Qt::CaseInsensitive);
qDebug() << str2; // "你是谁啊?我是凑企鹅"

2.6 修改指定位置字符

语法格式:通过下标运算符 str[index] = QChar; 进行修改。

讲解:可以像操作数组一样修改指定索引的字符。如果指定的序号太大,Qt 会自动在中间补充空格以扩充长度。

示例代码

QString str1 = "123456";
str1[0] = 'A'; // 变为 "A23456"
str1[7] = '7'; // 索引7超出当前长度,自动补空格,变为 "A23456 7"

2.7 数据类型转换

2.7.1 转换为数值(整数/浮点数)

函数原型

  • int toInt(bool *ok = nullptr, int base = 10) const;
  • double toDouble(bool *ok = nullptr) const;

讲解

  • ok:转换状态指针。转换成功则被赋值为 true,失败则为 false
  • base:进制基数(如 10 进制、16 进制)。默认为 10,若设为 0 则自动根据字符串前缀(如 0x)解析。
  • 同类方法还包括 toFloat(), toShort() 等,用法完全一致。

示例代码

// 1. 转换为整数
QString str1 = "365abc";
bool ret;
int num = str1.toInt(&ret, 10); // 包含非数字字符,ret 将为 false,转换失败
if (ret) {
    qDebug() << "转换成功:" << num;
} else {
    qDebug() << "转换失败";
}

QString str2 = "365";
num = str2.toInt(&ret, 16); // 按16进制转换
num = str2.toInt();         // 默认按10进制转换

// 2. 转换为浮点数
QString str3 = "3.14a";
double dNum = str3.toDouble(&ret); // 失败,含有字符 'a'
str3 = "3.14";
dNum = str3.toDouble();            // 成功

2.7.2 转换为 C 风格字符串(char *

函数原型std::string toStdString() const;

讲解:由于标准库和 Qt 的字符串底层编码与结构不同,通常需要先通过 toStdString() 转换为 std::string,再通过 .c_str() 获取临时的 const char* 指针。

示例代码

QString str1 = "A! a! o!";
const char* c_str1 = str1.toStdString().c_str();
std::cout << c_str1 << std::endl; // A! a! o!

2.8 删除数据

函数原型

  • 按位置删除:QString& remove(int position, int n);
  • 按子串删除:QString& remove(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive);
  • 清空串:void clear();

示例代码

QString str = "123456";
str.remove(0, 2); // 从索引 0 开始,删除 2 个字符,结果为 "3456"

QString str2 = "Rock is rock lover";
str2.remove("rock"); // 默认区分大小写,只删除小写 "rock"
str2.remove("rock", Qt::CaseInsensitive); // 不区分大小写,全部删除

// 清空字符串
QString str3 = "床前明月光";
str3.clear(); // 变为空串,长度为 0

2.9 获取子字符串

函数原型

  • 指定范围截取:QString mid(int position, int n = -1) const;
  • 头部截取:QString left(int n) const;
  • 尾部截取:QString right(int n) const;

讲解

  • mid():从指定 position 开始截取 n 个字符。如果 n 为 -1(默认),则截取到字符串末尾。
  • left(n):等价于 mid(0, n),获取左侧 n 个字符。
  • right(n):获取倒数最后 n 个字符。

示例代码

QString str = "床前明月光";
QString s1 = str.mid(2);    // 从索引2到结束 -> "明月光"
QString s2 = str.mid(2, 2); // 从索引2开始取2个字符 -> "明月"

QString s3 = str.left(2);   // 取左边2个字符 -> "床前"
QString s4 = str.right(3);  // 取右边3个字符 -> "明月光"

2.10 分割字符串

函数原型QStringList split(const QString &sep) const;

讲解:使用分隔符 sep 将字符串切分成多个子串,并存入 QStringList 容器中。

示例代码

QString str = "床前明月光 疑是地上霜 举头望明月 低头思故乡";
QStringList list = str.split(" "); // 按空格分割
int n = list.count();
for (int i = 0; i < n; i++)
{
    qDebug() << list[i]; // 逐行输出每句诗
}
posted @ 2026-07-12 13:39  学习笔记草稿存放账号  阅读(5)  评论(0)    收藏  举报