Qt Core 之 QString
QString
- 一、 为什么是 QString?
- 二、 创建与初始化
- 常用:
- **补充:**
- 三、 常用操作与成员函数
- 1. 字符串拼接
- 2. 字符串查询 与 判断
- 3. 字符串修改 与 截取
- 4. 字符串分割 与 列表拼接成字符串
- 5. 数字与字符串的转换
- 四、 与其他字符串类型的转换
- 五、 场景应用与实践
- 六、 注意点
QString
是 Qt 框架中用于处理字符串的核心类,在 Qt 开发中,涉及到与 Qt 的库交互时,使用 QString
,往往会比标准库的 std::string
更方便些。
Tips:使用
utf-8
编码格式,可以规避中文乱码的情况。
一、 为什么是 QString?
在 C++ 中,处理字符串通常使用 std::string
(或更古老的 char*
)。Qt 提供了 QString
,并非重复造轮子,而是为了解决一些关键问题:
- Unicode 支持:
QString
内部使用 UTF-16 编码,这意味着它可以无缝地存储和显示世界上几乎所有书写系统的字符(如英文、中文、阿拉伯文、表情符号 😊)。这是它与std::string
(本质是字节数组)最根本的区别。 - 隐式共享(写时复制):
QString
使用了隐式共享技术来优化内存和性能。多个QString
对象可以共享同一份字符串数据,只有在某个对象需要修改数据时,才会真正执行复制操作。这对传递大型字符串非常高效。 - 丰富的 API:
QString
提供了大量便捷的成员函数,用于字符串拼接、分割、查找、替换、大小写转换等操作,大大简化了字符串处理。 - 与 Qt 框架的无缝集成:几乎所有 Qt 的 API 都接受和返回
QString
,这使得它在 Qt 生态中是无可替代的。 - 编码转换: 内置多种编码转换功能。
简单来说:在 Qt 项目中,应该始终使用 QString
而不是 std::string
来处理用户可见的文本。
二、 创建与初始化
QString
有多种创建方式,使用前需要#include <QString>
。
通常使用 构造函数 初始化字符串。
常用:
#include <QString>
#include <QDebug>int main(){// 1. 仅声明QString Str;// 方式一:调用构造函数QString qstr1 = QString("Hello from C-string");// 方式二:隐式调用构造函数(常见,有微小的开销)QString qstr2 = "Hello from C-string";return 0;
}
方法二中,编译器会在背后悄悄地调用了 QString(const char*)
这个构造函数,创建一个临时的 QString
对象,然后再通过拷贝构造函数初始化 qstr,因此会有一点点开销。
补充:
#include <QString>
#include <QDebug>int main(){// 1. 空字符串QString emptyStr;// 2. 隐式调用构造函数,类似于C风格的字符串(const char*)构造// Qt会自动将const char*从本地编码转换为UTF-16。// Tips:在源文件中直接写中文等非ASCII字符,需确保文件编码为UTF-8(推荐)。QString str1 = "Hello, 世界!";// 3. 从另一个QString构造(拷贝构造,受益于隐式共享,开销很小)QString str2 = str1;// 4. 重复一个字符QString str3(5, 'Q'); // "QQQQQ"// 5. 使用 QStringLiteral 宏(推荐用于编译期字符串常量)// 此宏在编译期将字符串字面量直接转换为QString的内部格式,避免运行时的转换开销,性能最佳。QString str4 = QStringLiteral("性能更好的字符串常量");// 6. 使用 u"" 字面量(C++11及以上)// 这是另一种高效的初始化方式,直接从Unicode字面量创建QString。QString str5 = u"Unicode字符串";return 0;
}
三、 常用操作与成员函数
1. 字符串拼接
支持以下语法:
+
运算符append()
函数:追加arg()
函数:格式化拼接。 ✅推荐sprintf()
函数:格式化
为什么推荐方法三:
- 类型安全:在编译时由编译器检查参数类型是否正确,杜绝了因类型不匹配导致的运行时崩溃。
- 多语种翻译的支持:通过编号占位符(%1, %2)而非顺序占位符,让翻译人员能根据目标语言的语法灵活调整句子结构,实现地道的本地化,无需程序员修改代码。
简而言之,有利于翻译达到“信达雅”中的“达”,读起来不拗口。
具体用法案例:
#include <QString>
#include <QDebug>QString str1 = "Hello";
QString str2 = "World";int main(){// 方法1:使用 `+` 运算符QString result1 = str1 + " " + str2 + "!";// 方法2:使用 `append()` 函数(会修改原对象)str1.append(" ").append(str2).append("!");// 方法3:使用 `arg()` 函数(格式化拼接,推荐)// %1, %2 是占位符,会被后面的参数按顺序替换。QString name = "Alice";int age = 25;QString message = QString("Name: %1, Age: %2").arg(name).arg(age);// message = "Name: Alice, Age: 25"// 方法4:使用sprintf(不推荐,Qt5后建议使用arg)QString msg;msg.sprintf("Score: %d, Ratio: %.2f", 100, 0.95);return 0;
}
2. 字符串查询 与 判断
常用功能:
- 获取长度
- 是否空字符串
- 子串检查
- 子串开头或结束
- 查找子串位置
- 比较字符串是否相等
#include <QString>
#include <QDebug>QString s = "Hello Qt";int main(){// 获取长度int len = s.length(); // or s.size(), s.count()// 是否为空/为空字符串bool isEmpty = s.isEmpty();bool isNull = s.isNull(); // 注意:isEmpty返回true不一定isNull返回true// 判断是否包含子串bool hasQt = s.contains("Qt"); // truebool hasQtCase = s.contains("qt", Qt::CaseInsensitive); // true, 大小写不敏感// 判断是否以某子串开始/结束bool starts = s.startsWith("Hello"); // truebool ends = s.endsWith("World"); // false// 查找子串位置int index = s.indexOf("l"); // 2, 第一个'l'的位置int lastIndex = s.lastIndexOf("l"); // 3, 最后一个'l'的位置// 比较int cmp = s.compare("hello qt", Qt::CaseInsensitive); // 0,表示相等bool eq = (s == "Hello Qt"); // truereturn 0;
}
3. 字符串修改 与 截取
常用功能:
- 替换子串
- 去除空白
- 大小写转换
- 插入与删除
- 截取子串:可配合 查找字串位置
*IndexOf
函数 一起使用。
具体用法案例:
#include <QString>
#include <QDebug>QString s = "I like apples";
int main(){// 替换s.replace("apples", "oranges"); // "I like oranges"// 去除首尾空白字符(非常常用,处理用户输入)QString userInput = " hello \n";QString trimmed = userInput.trimmed(); // "hello" (不修改原对象)// userInput.trim(); // 这会修改原对象本身// 改变大小写QString lower = s.toLower(); // "i like apples"QString upper = s.toUpper(); // "I LIKE APPLES"// 插入与删除s.insert(2, "really "); // "I really like apples"s.remove(2, 7); // 从索引2开始删除7个字符 -> "I like apples"// 截取子串QString sub1 = s.mid(2); // "like apples" (从索引2到结尾)QString sub2 = s.mid(2, 4); // "like" (从索引2开始,截取4个字符)QString left = s.left(5); // "I lik"QString right = s.right(6); // "apples"return 0;
}
4. 字符串分割 与 列表拼接成字符串
常用功能:
- 字符串的分割:返回给
QStringList
对象。 - 字符串列表的拼接:将字符串列表中的元素拼接成字符串。
具体用法案例:
#include <QString>
#include <QDebug>QString path = "usr/local/bin";int main(){// 分割:字符串 -> QStringListQStringList list = path.split('/');// list: ["usr", "local", "bin"]// 拼接:QStringList -> 字符串QString newPath = list.join('\\');// newPath: "usr\\local\\bin"return 0;
}
5. 数字与字符串的转换
QString
配备了数字与QString之间的转换函数。
#include <QString>
#include <QDebug>
int main(){// 数字 -> QStringQString s1 = QString::number(42); // "42"QString s2 = QString::number(3.14, 'f', 2); // "3.14" (格式'f', 精度2位)// QString -> 数字bool ok;int i = s1.toInt(&ok); // i=42, ok=truedouble d = s2.toDouble(&ok); // d=3.14, ok=truefloat f = s2.toFloat(&ok);// 如果转换失败,ok会被设为false,数字值设为0int bad = QString("hello").toInt(&ok); // bad=0, ok=falsereturn 0;
}
四、 与其他字符串类型的转换
其他的常见需求,主要包括:
QString
与std::string
之间QByteArray
与QString
之间
推荐规范示例:
#include <QString>
#include <QDebug>
int main(){QString qstr = "Hello, Qt";// 1. QString -> std::string// 注意:toStdString() 返回 UTF-8 编码的 std::string。std::string std_str = qstr.toStdString();// 2. std::string -> QStringQString from_std = QString::fromStdString(std_str);// 3. QString -> const char* (QByteArray)// 注意:toUtf8() 返回一个临时的 QByteArray 对象。// 不要保存这个data()指针,它的生命周期只在当前行!const char* c_str = qstr.toUtf8().constData(); // 正确用法:立即使用QByteArray byteArray = qstr.toUtf8(); // 如果需要持久化,保存QByteArrayconst char* persistent_c_str = byteArray.constData();// 4. const char* -> QStringQString from_c_str = QString::fromUtf8(c_str);// 5. QString -> 平台相关的本地编码 (Local 8-bit),依赖操作系统// 通常不推荐,除非与某些老旧的本地API交互。QByteArray localBytes = qstr.toLocal8Bit();// 6. 平台相关的本地编码 -> QStringQString from_local = QString::fromLocal8Bit(localBytes);return 0;
}
五、 场景应用与实践
应用场景:
- 处理用户界面文本:所有
QLabel
、QPushButton
等控件设置的文本都应使用QString
。 - 文件路径操作:
QFile
,QDir
等类都使用QString
表示路径,完美支持中文等 Unicode 路径名。 - 网络数据接收:从网络接收的 UTF-8/UTF-16 数据,可以方便地用
QString::fromUtf8()
等进行转换。 - 拼接复杂消息:使用
arg()
方法进行格式化,易于阅读和后续的国际化翻译。 - 处理用户输入:使用
trimmed()
去除用户输入的首尾空白字符。
最佳实践:
- 性能:对于编译期的字符串常量,优先使用
QStringLiteral("text")
。 - 编码:确保你的源代码文件保存为 UTF-8 编码,以避免中文乱码问题。
- 转换:与 C 库或系统 API 交互时,注意使用
toUtf8()
、toLocal8Bit()
进行正确的编码转换,并注意指针的生命周期。 - 隐式共享:放心地以值传递方式返回或传递
QString
,隐式共享机制保证了其高性能。
六、 注意点
constData()
指针的生命周期:// 错误!temp对象在这一行结束后就被销毁,c_str成了悬空指针! const char* c_str = myQString.toUtf8().constData();// 正确!先将QByteArray保存到一个变量,延长其生命周期。 QByteArray ba = myQString.toUtf8(); const char* safe_c_str = ba.constData();
- “空”与“null”的区别:
- 默认构造的
QString()
既是null
也是empty
。 QString("")
是empty
但不是null
。- 在大多数情况下,你应该使用
isEmpty()
来判断字符串是否有效。
- 默认构造的
- 跨线程操作:
QString
是可重入(Reentrant) 的,但不是线程安全(Thread-safe) 的。多个线程同时修改同一个QString
对象需要外部同步机制(如互斥锁)。
持续更新中。。。。。。。