本页内容

字符串数据类

概述

本页概述了 Qt 中的字符串类,特别是数量众多的字符串容器,以及如何在对性能要求极高的代码中高效地使用它们。

以下关于高效使用的指导,主要面向正在处理包含大量字符串处理的、对性能要求极高的代码的经验丰富的开发者。例如,解析器或文本文件生成器。通常情况下,QString 可用于任何场景,性能良好。它还提供了处理多种编码的 API(例如QString::fromLatin1())。对于许多应用程序,特别是当字符串处理对性能影响微乎其微时,QString 将是一个简单且足够的解决方案。某些 Qt 函数会返回QStringView 。如有需要,可通过QStringView::toString() 将其转换为QString 。

实用技巧

以下三条规则可在不大幅增加复杂性的情况下显著提升字符串处理效率。遵循这些规则,在大多数情况下可获得近乎最佳的性能。前两条规则涉及字符串字面量的编码及其在源代码中的标记。第三条规则涉及使用字符串片段时的深度复制。

  • 所有仅包含 ASCII 字符的字符串(例如日志消息)均可使用 Latin-1 编码。请使用string literal "foo"_L1 。若缺少此后缀,源代码中的字符串字面量将被视为 UTF-8 编码,处理速度会变慢。通常应尽量使用最精简的编码,在许多情况下即为 Latin-1。
  • 用户可见的字符串通常需要进行翻译,因此应通过QObject::tr() 函数进行处理。该函数接受一个字符串字面量(const char 数组),并返回一个QString ,其采用所有 UI 元素所要求的 UTF-16 编码。如果不使用翻译基础设施,则应在整个应用程序中统一使用 UTF-16 编码。 使用字符串字面量u"foo" 来创建UTF-16字符串字面量,或使用Qt特有的字面量u"foo"_s 直接创建QString 。
  • 在处理QString 的各个部分时,请勿将每个部分复制到独立的QString 对象中,而应创建QStringView 对象。这些对象可通过QStringView::toString()转换回QString ,但应尽可能避免这样做。如果函数返回QStringView ,在可能的情况下继续使用该类最为高效。其API与常量QString 类似。

高效使用

要高效地使用字符串类,应理解以下三个概念:

  • 编码
  • 拥有型和非拥有型容器
  • 字面量

编码

在编码方面,Qt 以某种形式支持 UTF-16、UTF-8、Latin-1(ISO 8859-1)和 US-ASCII(即 Latin-1 和 UTF-8 的公共子集)。

  • Latin-1 是一种每个字符使用一个字节的字符编码,这使其成为效率最高但同时也最受限的编码。
  • UTF-8 是一种可变长度的字符编码,使用 1 到 4 个字节来编码所有字符。它与 US-ASCII 向后兼容,是源代码和类似文件的常用编码。Qt 默认源代码采用 UTF-8 编码。
  • UTF-16 是一种可变长度编码,每个字符占用 2 或 4 个字节。它是 Qt 中面向用户的文本的常用编码。

有关更多信息,请参阅Qt 中关于 Unicode 支持的信息。

其他编码形式可通过单个函数(如 `QString::fromUcs4()`)或 `QStringConverter ` 类来支持。此外,Qt 还提供了一个与编码无关的数据容器 `QByteArray`,该容器非常适合存储二进制数据。`QAnyStringView ` 会跟踪底层字符串的编码,因此可以提供对采用任何受支持编码标准的字符串的视图。

编码之间的转换开销较大,因此应尽可能避免。另一方面,更紧凑的编码(特别是对于字符串字面量)可以减小二进制文件大小,从而提高性能。 当字符串字面量可以用Latin-1表示时,即使最终需要转换为UTF-16,它也能在这些相互冲突的因素之间取得良好的平衡。当必须将Latin-1字符串转换为QString 时,该操作的效率相对较高。

功能

字符串类还可以根据其支持的功能进一步区分。一个主要区别在于它们是否拥有(并因此控制)其数据,还是仅仅引用存储在其他地方的数据。前者称为拥有容器,后者称为非拥有容器或视图。 非拥有型容器通常仅记录指向数据起始位置的指针及其大小,因此结构轻量且开销低,但其有效性仅在数据可用期间内维持。 拥有型字符串管理其存储数据的内存,确保数据在容器生命周期内始终可用,但其创建和销毁会产生分配和释放内存的开销。视图通常仅支持拥有型字符串功能的一小部分,且无法修改底层数据。

因此,字符串视图特别适合表示较大字符串的片段(例如在解析器中),而拥有型字符串则适用于持久存储(例如类中的成员)。 当函数返回其构建的字符串(例如通过组合片段)时,必须返回拥有型字符串;但当函数返回某个持久存储字符串的一部分时,视图通常更合适。

请注意,Qt 中的拥有容器会隐式共享数据,这意味着按值传递或返回大型容器也是高效的,尽管由于引用计数的原因,其效率略低于按引用传递。 若要利用 Qt 类的隐式数据共享机制,必须将字符串作为拥有容器或其引用进行传递。转换为视图及反向转换总会生成数据的额外副本。

最后,Qt 提供了用于单个字符、字符串列表和字符串匹配器的类。除少数例外情况外,这些类适用于 Qt 支持的大多数编码标准。 更高层次的功能由专用类提供,例如QLocale 或QTextBoundaryFinder 。这些高级类通常依赖于QString 及其UTF-16编码。某些类是模板类,可与所有可用的字符串类配合使用。

字面量

C++ 标准提供了字符串字面量,用于在编译时创建字符串。 既有由语言定义的字符串字面量,也有由 Qt 定义的字面量,即所谓的用户定义字面量。C++ 定义的字符串字面量用双引号括起,并可带有前缀来告知编译器如何解释其内容。对于 Qt 而言,UTF-16 字符串字面量u"foo" 最为重要。 它会在编译时创建一个采用 UTF-16 编码的字符串,从而省去了运行时从其他编码转换的必要。可以轻松高效地从该字符串构建QStringView ,因此可以将其传递给接受QStringView 参数(或相应地,QAnyStringView )的函数。

用户定义的字面量与 C++ 定义的字面量形式相同,但在闭引号后添加了一个后缀。编码仍由前缀决定,但生成的字面量用于构造某个用户定义类型的对象。 因此,Qt 为其部分字符串类型定义了这些形式:u"foo"_s 对应QString ,"foo"_L1 对应QLatin1StringView ,u"foo"_ba 对应QByteArray 。这些形式是通过StringLiterals Namespace 提供的。一个普通的 C++ 字符串字面量"foo" 将被解释为 UTF-8,而将其转换为QString (即 UTF-16)将消耗较多资源。 当字符串字面量为纯 ASCII 格式时,请使用"foo"_L1 将其解释为 Latin-1,从而获得上述提到的各项优势。

基本字符串类

下表概述了适用于各种文本编码标准的基本字符串类。

编码C++ 字符串字面量Qt 用户自定义字面量C++ 字符Qt 字符拥有型字符串非拥有型字符串
Latin-1-""_L1-QLatin1Char-QLatin1StringView
UTF-8u8""-char8_t--QUtf8StringView
UTF-16u""u""_schar16_tQCharQStringQStringView
二进制/无-""_bastd::byte-QByteArrayQByteArrayView
灵活任意----QAnyStringView

部分缺失的条目可以用 C++ 的内置类型和标准库类型替代:一个拥有 Latin-1 或 UTF-8 编码的字符串可以是 `std::string ` 或任何 8 位 `char ` 数组。`QStringView ` 还可以引用任何 16 位字符数组,例如某些平台上的 `std::u16string` 或 `std::wstring`。

Qt 还为其中某些类型提供了专用列表,即 `QStringList ` 和 `QByteArrayView`,以及匹配器 `QLatin1StringMatcher ` 和 `QByteArrayMatcher`。这些匹配器还有在编译时创建的静态版本,即 `QStaticLatin1StringMatcher ` 和 `QStaticByteArrayMatcher`。

此外值得注意的是:

  • QStringLiteral 是一个宏,其作用与u"foo"_s 完全相同,且无需使用StringLiterals Namespace 即可使用。建议您使用现代字符串字面量。
  • QLatin1String 是QLatin1StringView 的同义词,仅为向后兼容而保留。它并非拥有型字符串,未来版本中可能会被移除。
  • QAnyStringView 该类为采用三种受支持编码之一(任意一种)的字符串提供视图。编码信息与数据引用一同存储。该类非常适合用于创建能够处理各种字符串类型和编码的接口。与其他类不同,它不会直接对 `QAnyStringView ` 进行任何处理。 处理是在底层的QLatin1StringView 、QUtf8StringView 或QStringView 上,以相应的编码形式进行的。若要在将该类作为参数的自定义函数中实现相同功能,请使用QAnyStringView::visit()。
  • 在 UTF-8 编码的源代码文件中,构建包含非 ASCII 字符的QLatin1StringView 并非易事,需要特殊处理,请参阅QLatin1StringView 的文档。
  • QStringRef 是QString 的一部分的引用,出于向后兼容性考虑,可在Qt5Compat模块中使用。它应被QStringView 所取代。

更多提供附加功能的高级类主要与 `QString ` 配合使用,因此采用 UTF-16 编码。这些类包括:

某些类是模板类,或者具有灵活的 API,可与各种字符串类配合使用。这些类包括

应使用哪个字符串类?

使用字符串类的一般指导原则是:

  • 避免复制和内存分配,
  • 避免编码转换,以及
  • 选择最紧凑的编码方式。

Qt 提供了许多功能来避免内存分配。大多数 Qt 容器都采用了数据的隐式共享机制。要使隐式共享生效,必须存在同一类的连续链——从 `QString ` 转换为 `QStringView ` 再转换回来,将导致两个不共享数据的 `QStrings `。 因此,函数需要将数据作为QString (值或引用均可)传递。在隐式数据共享的情况下,无法提取字符串的局部内容。若要使用较长字符串的局部内容,请使用字符串视图(string views),这是一种显式数据共享的形式。

通过坚持使用特定编码,可以减少编码之间的转换。例如,如果接收到的数据(如UTF-8编码)无需转换为其他编码,则最好以UTF-8格式进行存储和处理。相同编码的字符串之间进行比较速度最快,大多数其他操作也是如此。 如果某种编码的字符串经常被比较或转换为其他编码,则将其转换并存储一次可能会更有利。某些操作提供了许多重载(或QAnyStringView 重载)来处理各种字符串类型和编码,如果无法使用相同的编码,这些重载应作为优化性能的第二选择。 在调用函数前进行显式编码转换应作为最后手段,仅在别无选择时才使用。Latin-1 是一种非常简单的编码,Latin-1 与任何其他编码之间的操作效率几乎与同一编码之间的操作一样高。

当没有其他约束条件决定编码时,应选择效率最高的编码(从最高到最低依次为 Latin-1、UTF-8、UTF-16)。对于错误处理和日志记录,QLatin1StringView 通常就足够了。Qt 中用户可见的字符串始终是QString 类型,因此采用 UTF-16 编码。 因此,在用户可见字符串的整个生命周期中,使用QStrings 、QStringViews 和QStringLiterals 最为有效。QObject::tr() 函数可提供正确的编码和类型。若编码不重要(例如存储二进制数据)或编码未知时,应使用QByteArray 。

用于创建 API 的 String 类

用于实现最佳 API 的 String 类

成员变量

在几乎所有情况下,成员变量都应采用拥有者类型。只有当被引用的拥有者字符串的生命周期被保证超过该对象的生命周期时,才能将视图用作成员变量。

函数参数

在大多数情况下,函数参数应为具有适当编码的字符串视图。可使用QAnyStringView 作为参数以支持多种编码,并可在内部使用QAnyStringView::visit() 来分流至针对不同编码的函数。如果函数仅限于单一编码,则应使用QLatin1StringView 、QUtf8StringView 、QStringView 或QByteArrayView 。

如果函数将参数保存在拥有型字符串中(通常是设置函数),则将该拥有型字符串作为函数参数使用最为高效,这样可以利用 Qt 的隐式数据共享功能。拥有型字符串可以作为 `const ` 引用传递。 使用多种拥有型和非拥有型字符串类型重载函数可能会导致重载歧义,应予以避免。Qt 中的拥有型字符串类型可自动转换为其非拥有型版本或转换为 `QAnyStringView`。

返回值

临时字符串必须作为拥有型字符串返回,通常为QString 。如果返回的字符串在编译时已知,请使用u"foo"_s 在编译时构建QString 结构。 如果从函数中完整返回现有的拥有型字符串(例如QString ),最有效的方法是按引用返回。也可以按值返回,以便将来能够返回临时字符串。Qt 采用的隐式共享机制,可避免按值返回时因内存分配和复制带来的性能影响。

现有字符串的片段可通过适当编码的字符串视图高效返回,例如参见QRegularExpressionMatch::capturedView(),该函数返回一个QStringView 。

用于调用 API 的 String 类

用于调用函数的字符串类

要高效使用 Qt API,应尽量使函数参数类型与之匹配。若选择受限,Qt 将进行各种转换:拥有型字符串会被隐式转换为非拥有型字符串,非拥有型字符串可以创建其对应的拥有型字符串,例如参见QStringView::toString()。 编码转换在许多情况下会隐式进行,但应尽可能避免。为避免 UTF-8 字符串被意外隐式转换,可启用宏QT_NO_CAST_FROM_ASCII 。

若需在运行时组装字符串后再将其传递给函数,则必须使用拥有型字符串,因此应使用 `QString`。若函数参数为 `QStringView ` 或 `QAnyStringView `,则会进行隐式转换。

如果字符串在编译时已知,则有优化的余地。 如果函数接受QString ,你应该使用u"foo"_s 或QStringLiteral 宏来创建它。如果函数期望QStringView ,最好使用普通的 UTF-16 字符串字面量u"foo" 来构造;如果期望QLatin1StringView ,则使用"foo"_L1 进行构造。如果你可以在两者之间进行选择(例如,如果函数期望QAnyStringView ),请使用最紧凑的编码,通常是 Latin-1。

QAnyStringView

通过 QString API 的只读子集,统一处理 Latin-1、UTF-8 或 UTF-16 字符串

QByteArray

字节数组

QByteArrayList

字节数组列表

QByteArrayMatcher

保存一串字节,可在字节数组中快速进行匹配

QByteArrayView

通过 QByteArray API 的只读子集查看字节数组

QChar

16 位 Unicode 字符

QCollator

根据本地化的排序规则对字符串进行比较

QCollatorSortKey

可用于加快字符串排序速度

QLatin1Char

8 位 ASCII/Latin-1 字符

QLatin1StringMatcher

针对 Latin-1 文本中的子字符串进行了优化搜索

QLatin1StringView

US-ASCII/Latin-1编码字符串字面量的轻量级封装

QLocale

在各种语言中实现数字与其字符串表示形式之间的转换

QRegularExpression

使用正则表达式进行模式匹配

QRegularExpressionMatch

将 QRegularExpression 与字符串进行匹配的结果

QRegularExpressionMatchIterator

QRegularExpression 对象对字符串进行全局匹配后的结果迭代器

QStaticByteArrayMatcher

QByteArrayMatcher 的编译时版本

QStaticLatin1StringMatcher

QLatin1StringMatcher 的编译时版本

QString

Unicode 字符串

QStringConverter

文本编码和解码的基类

QStringDecoder

基于状态的文本解码器

QStringEncoder

基于状态的文本编码器

QStringList

字符串列表

QStringMatcher

包含一串字符,可在 Unicode 字符串中快速进行匹配

QStringRef

QString 子字符串的轻量级封装类

QStringTokenizer

根据给定的分隔符将字符串拆分为词素

QStringView

提供对 UTF-16 字符串的统一视图,并包含 QString API 的只读子集

QTextBoundaryFinder

在字符串中查找 Unicode 文本边界的方法

QTextStream

用于读写文本的便捷接口

QUtf8StringView

通过 QString API 的只读子集提供对 UTF-8 字符串的统一视图

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.