更适合中国宝宝体质的QString解析(2024新版Qt6.5LTS)

浅谈QString(2024新版)

全文一共约16000字,写于2024年4、5月,发布日期2024年5月9日
原文
本文使用例子和源码已上传配套资源
源码

1. 简介

  • QString是Qt中的一个类,用于存储字符串,且没有父类。
  • 存储字符串的每一个字符是一个QChar类型,QChar使用的是UTF-16编码,也就是每一个字符占两字节2B16bit
  • UTF-16是一种Unicode编码,可以表示汉字,汉字在QString中是一个字符、一个QChar
  • 对于编码值大于6553516bit)的字符集,Unicode会使用代理编码对(surrogate pairs)来储存,例如用两个QChars表示古希腊文字或补充私人使用区(Supplementary Private Use Area)等。

1.1 编码与字符集

  • ASCII
    • ASCII是基本的字符集,用1字节编码。
    • 其中编码值0~127包含英语中的大小写字母、数字0~9、标点符号、换行符、制表符、退格符等
  • Latin1
    • Latin1字符集是对ASCII字符集的扩展,也是用一字节编码,它用128~255表示拉丁字母表中特殊语言字符;
  • Unicode
    • ASCIILatin1都是用1字节编码的,最多只有256个字符,无法表示汉语、日语等其他语言里的字符,因此又出现了Unicode编码。
    • Unicode增加一个或多个高位字节对Latin1进行扩展。当这些高位字节为0时,低字节数据就是Latin1字符。
    • Unicode支持大多数国家和地区语言文字,所以被广泛使用。
    • 官网:Unicode – The World Standard for Text and Emoji
  • Unicode存储方案
    • Unicode有多种存储方案,其中UTF-8最少用1字节编码,可以使用1~4字节编码。
    • UTF-16最少使用2字节编码,可以使用2字节或4字节编码。
    • UTF-8可以兼容Latin1编码,所以被广泛使用,Qt Creator存储的C++头文件和源程序文件都默认使用UTF-8的存储方案(或叫成UTF-8编码)。

1.2 QString的隐式共享

implicitShared

  • 简介

    • 隐式共享又称回写复制copy-on-write or value semantics)。当两个对象共享同一份数据(通过浅拷贝实现数据块共享)时,如果数据不改变,则不进行数据的复制。
    • 而当某个对象需要改变数据时,则执行深拷贝。
  • 深浅拷贝

    • 在处理共享对象时,使用深拷贝和浅拷贝两种方式复制对象。
    • 深拷贝指生成对象的完整的复制品,所占空间、资源等。
    • 而浅拷贝仅复制指向共享对象的指针
    • 执行一个深拷贝的代价比较昂贵,要占用更多的内存和CPU资源,而浅拷贝的效率很高,它仅需设置一个指向共享数据块的指针及修改引用计数reference count)的值。
  • 举个例子(栈空间内)

    QString str1_t = "expend";
    QString str2_t = str1_t;	//1
    str2_t[2] = 't';			//2
    str1_t = str2_t;			//3
    
    1. QString str2_t = str1_t;
      • 将字符串对象str1_t赋值给另一个字符串str2_t,由QString的拷贝构造函数完成str2_t的初始化。
      • 在对str2_t赋值的时候,将发生一次浅拷贝,导致两个QString对象都指向同一个数据结构。
      • 该数据结构除了保存字符串"expend"外,还保存了一个引用计数器,用来记录字符串数据的引用次数。
      • 这里str1_tstr2_t指向同一个数据结构,所以reference count的值为2。
    2. str2_t[2] = 't';
      • 对QString对象str2_t的修改会导致一次深拷贝,使得str2_t指向一个新的、不同于str1_t的数据结构,保存的字符串为"extend"
      • 该数据结构的reference count为1,因为只有str2_t指向这个数据结构。
      • 同时原来的数据结构会修改reference count为1,这意味着该数据结构没有被共享。
    3. str1_t = str2_t;
      • str2_t赋值给str1_t,此时str1_t将它指向的数据结构的reference count修改为0,也就是说,没有QString对象再使用这个数据结构了。
      • 因此,str1_t指向的数据结构将会从内存中释放掉,str2_t指向的数据结构的reference count为2。

1.3 QString的内存分配机制

Preallocates

  • QString在一个连续的内存块中保存字符串数据,当字符串长度不断增加时,QString需要重新分配内存空间,以便有足够的空间保存增加的字符串。

  • If you are building a QString gradually and know in advance approximately how many characters the QString will contain, you can call reserve(), asking QString to preallocate a certain amount of memory. You can also call capacity() to find out how much memory QString actually allocated.

  • Qt官方文档Container Classes | Qt Core 6.7.1分配策略Growth Strategies)如下:

    • a n = 2 ( n + 3 ) − 8 a_n=2^{(n+3)}-8 an=2(n+3)8

    • 其中n重新分配的次数,注意分配的是多少个QChar字符。一个字符占2字节(byte),16位(bit)。QString内部使用Unicode(UTF-16)编码。

    • 注意实际分配是受32位还是64位系统影响,具体可以参考例子自己试一试。

  • 例如QString::append()函数源码段:

    • {
          if (d->ref.isShared() || uint(d->size + str.d->size) + 1u > d->alloc)
          	reallocData(uint(d->size + str.d->size) + 1u, true);
      	memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar));
      	d->size += str.d->size;
      	d->data()[d->size] = '\0';
      }
      
    • 可以看到,用了reallocData()函数重新分配内存空间。

    • 其中有个allocOptions选项会与上(|=)QArrayData::Grow,也就是0x8

    • 最后会通过qCalculateGrowingBlockSize()函数去计算需要重新分配内存空间的大小。

    • if (Q_UNLIKELY(int(morebytes) < 0)) {
              // catches morebytes == 2GB
              // grow by half the difference between bytes and morebytes
              bytes += (morebytes - bytes) / 2;
          } else {
              bytes = morebytes;
          }
      
  • 举个具体的例子:

    • void TestQStringCapacity::test_m()
      {
          QString testStr_t = "";
          qint64 recordCapacity_t = testStr_t.capacity();
          qDebug() << "Start!\tCapacity:" << testStr_t.capacity() << "Size:" << testStr_t.size();
          for (int i = 0; i < 10000; ++i) {
              testStr_t.append("a");
              if (Q_UNLIKELY(!!(testStr_t.capacity() - recordCapacity_t))) {
                  qDebug() << "test Str has been expanded!" << QString("Capacity:%1 Size:%2 At %3 Cycle.").arg(testStr_t.capacity()).arg(testStr_t.size()).arg(i);
                  recordCapacity_t = testStr_t.capacity();
              }
          }
          qDebug() << "End!\tCapacity:" << testStr_t.capacity() << "Size:" << testStr_t.size();
      }
      
    • 根据QString的内存分配策略,这个循环操作将导致11次内存重新分配:8, 24, 56, 120, 248, 504, 1016, 2040, 4088, 8184, 16376

    • 最后一次内存重新分配操作后,QString对象testStr_t具有一个16376Unicode字符大小的内存块(32752字节),其中有10000个字符空间被使用(20000B)。

    • 实际打印的Capacity跟32位还是64位编译环境、字符后的\0、Qt版本等其他因素有关。

    • 例如下面是Qt5.15.2 MSVC2019 32bit编译的结果:

      Start!	Capacity: 0 Size: 0
      test Str has been expanded! "Capacity:7 Size:1 At 0 Cycle."
      test Str has been expanded! "Capacity:23 Size:8 At 7 Cycle."
      test Str has been expanded! "Capacity:55 Size:24 At 23 Cycle."
      。。。
      test Str has been expanded! "Capacity:4087 Size:2040 At 2039 Cycle."
      test Str has been expanded! "Capacity:8183 Size:4088 At 4087 Cycle."
      test Str has been expanded! "Capacity:16375 Size:8184 At 8183 Cycle."
      End!	Capacity: 16375 Size: 10000
      
    • 下面是Qt5.15.2 MinGW 64bit编译的结果:

      Start!	Capacity: 0 Size: 0
      test Str has been expanded! "Capacity:3 Size:1 At 0 Cycle."
      test Str has been expanded! "Capacity:19 Size:4 At 3 Cycle."
      test Str has been expanded! "Capacity:51 Size:20 At 19 Cycle."
      test Str has been expanded! "Capacity:115 Size:52 At 51 Cycle."
      。。。
      test Str has been expanded! "Capacity:16371 Size:8180 At 8179 Cycle."
      End!	Capacity: 16371 Size: 10000
      

2. QChar

2.1 中文帮助文档:

2.2 常用的函数

函数名称功能返回值
isDigit() const判断该字符是否为0~9的数字bool
isLetter() const判断该字符是否是字母,注意,汉字也是Letterbool
isLetterOrNumber() const是否为字母或数字bool
isLower() const是否为小写字母bool
isUpper() const是否为大写字母bool
isMark() const是否为记号bool
isNonCharacter() const判断是否是非文字字符,例如Unicode编码0xfffe~0xffff之间bool
isNull() const判断字符编码是否为0x0000,也就是’\0’bool
isNumber() const判断该字符是否为一个数,不仅包括0~9,还包括字符①、⑨bool
isPrint() const是否为可打印字符bool
isPunct() const是否为标点符号bool
isSpace() const是否为空白符,包括空格、制表符bool
isSymbol() const是否为符号,例如bool
toLatin1() const返回于Qchar字符等效的Latin1字符,如果无等效字符则返回’\0’char
toLower() const返回字母的小写形式,如果该字符不是字母,则返回其本身QChar
toUpper() const返回字母的大写形式,如果该字符不是字母,则返回其本身Qchar
unicode() constunicode()返回该字符的16位Unicode编码数值char16_t、char16_t &

2.3 QChar字符与Latin1字符互相转换

  • QChar中有个函数toLatin1()将该字符转换位Latin1字符,也就是将UTF-16编码的字符(2字节)转换为1字节的Latin1编码的字符;
  • 只有当字符的编码为0~255时,该函数才有意义。
  • 同样的,可以将Latin1字符转换为QChar字符;
    • 静态函数:QChar QChar::fromLatin1(char c)
    • QChar构造函数:QChar::QChar(QLatin1Char ch)QChar::QChar(char ch)(当宏QT_NO_CAST_FROM_ASCII被定义的时候不可用)、QChar::QChar(uchar ch)(当宏QT_NO_CAST_FROM_ASCIIQT_RESTRICTED_CAST_FROM_ASCII被定义的时候不可用);

2.4 Qchar字符的Unicode编码

  • 可以通过unicode()函数获取任何一个字符的UTF-16编码数值;

  • 也可以通过QChar QChar::fromUcs2(char16_t c)这个静态函数来从UTF-16编码得到一个字符(注意,该函数是Qt6.0以后才有的);

  • 或者通过QChar的构造函数QChar::QChar(char16_t ch)构造一个字符;

  • 例如:

    • QString str_t("你好,世界");
      str_t[3] = QChar(0x4e2d);
      str_t[4] = QChar::fromUcs2(0x56fd);
      
    • 该字符串的内容从"你好世界"变成了"你好中国";

  • 注意

  • 如果字符的UTF-16编码超过了Latin1的编码范围(也就是超过了255),就不能直接传递字符用于构造QChar对象,例如:

  • str_t[4] = QChar('国'); //错误的

  • Qt源程序采用UTF-8编码储存文件,源代码中的"国"是2字节的UTF-8编码,QChar没有这种类型参数的构造函数;

参考链接:

3. QString常用功能函数

所用版本:Qt 6.5 LTS

Qt6.5废弃的一些函数:Obsolete Members for QString | Qt Core 6.5.5

在QString中的所有函数都是可重入且线程安全的Reentrancy and Thread-Safety

3.1

append

QString &QString::append(const QString &str)
作用:在末尾追加字符/字符串

  • 除此之外还有7个重载函数
  • 追加函数append()是非常快的(时间复杂度为O(1)常量级别),因为QString用了预分配内存分配机制(空间换时间)
  • 2个重载函数是QT6之后引入的:
    • QString &QString::append(QStringView v) [since 6.0]
    • QString &QString::append(QUtf8StringView str) [since 6.5]
insert

QString &QString::insert(qsizetype position, const QString &str)

作用:在给定位置的前面插入字符串

  • 除此之外还有7个重载函数
  • 注意:如果给定插入的位置position比原字符串还大,则从原字符串末尾一直到position的位置会用空格代替;
  • 该函数返回的是*this,所以会修改原字符串的内容;
  • 2个重载函数是QT6之后引入的:
    • QString &QString::insert(qsizetype position, QStringView str) [since 6.0]
    • QString &QString::insert(qsizetype position, QUtf8StringView str) [since 6.5]
prepend

QString &QString::prepend(const QString &str)

作用:在最前面追加字符/字符串

  • 除此之外还有7个重载函数
  • 描述和append()相同
  • 2个重载函数是QT6之后引入的:
    • QString &QString::prepend(QStringView str) [since 6.0]
    • QString &QString::prepend(QUtf8StringView str) [since 6.5]
push_back

void QString::push_back(const QString &other)

  • 除此之外还有1个重载函数
  • 这个函数是为了兼容STL而提供的;
  • 该函数和append()完全一致;
push_front

void QString::push_front(const QString &other)

  • 除此之外还有1个重载函数
  • 这个函数是为了兼容STL而提供的;
  • 该函数和prepend()完全一致;
repeated

QString QString::repeated(qsizetype times) const

作用:返回原字符串拷贝的字符串,返回后的字符串由重复原字符串组成

  • 如果times<1,则会返回一个空串

3.2 (截)

chop

void QString::chop(qsizetype n)
作用:删除该字符串最后的n个字符

  • 如果n>=字符串大小,则删完;
  • 如果n为负数,则不删;
chopped
  1. QString QString::chopped(qsizetype len) const
    作用:返回该字符串从最左边开始长度为len的字符串
    • len为负或者大于字符串长度会产生不可预知;
clear

void QString::clear()
作用:清空字符串

  • isEmpty()和isNull都是true;
erase

QString::iterator QString::erase(QString::const_iterator first, QString::const_iterator last) [since 6.1]

作用:删除从迭代器first到迭代器last位置的字符串,并且返回删除字符串紧接着之后位置的迭代器

  • 除此之外还有1个重载函数

  • 注意,删除区间是半开式的,可以理解为:[first, last),也就是删除first所在位置,但不删除last

  • 删除之后,返回的迭代器其实也就是last

  • 两个函数都是QT6新加入的函数,还有一个重载函数为:

    • QString::iterator QString::erase(QString::const_iterator it) [since 6.5]

    • QString c = "abc";
      auto it = c.erase(c.cbegin());
      //删除后c字符串为:"bc"
      //迭代器it所指的位置为'b'
      
first / last

QString QString::first(qsizetype n) const [since 6.0]

作用:返回前n个字符的字符串

  • 该函数自从Qt6.0之后引入;
  • 如果n<0或n>size就会出现不可预知的问题;

QString QString::last(qsizetype n) const [since 6.0]

作用:返回后n个字符的字符串

  • first()

引入该函数是在预先直到需要截取的字符串不会超过原始字符串,用这两个函数会比用left()right()

left* / right*

共有4个截取字符串头尾的函数:

如果预先知道n不会超过边界,则请使用first/left(),比这些函数要快;

QString QString::left(qsizetype n) const

  • 作用:返回原始字符串左边的n个字符串

  • 如果n超过边界则会返回原始字符串(n大于原始字符串大小或n小于0的时候);

QString QString::leftJustified(qsizetype width, QChar fill = u' ', bool truncate = false) const

  • 作用:返回是否有填充的左边部分字符串
  • 如果给定的width大于原字符串的长度,则多余的部分全部使用fill的字符来填充;
  • truncate代表是否截取字符串,默认设置为不截取,如果要类似left()的效果,则要设置为true

QString QString::right(qsizetype n) const

  • 作用:返回原始字符串右边的n个字符串
  • 描述同left()类似;

QString QString::rightJustified(qsizetype width, QChar fill = u' ', bool truncate = false) const

  • 作用:返回是否有填充的右边部分字符串
  • 描述同leftJustified()类似,会在字符串最前面填充;
mid / sliced

有两个函数可以从字符串中间截取指定长度的字符串;

QString QString::mid(qsizetype position, qsizetype n = -1) const

  • 作用:截取从position开始,包含position,长度为n的字符串
  • 如果预先直到截取的长度不会超过原字符串的边界,则使用sliced()函数更快;
  • 如果position超过了原字符串的边界,则会返回空字符串;
  • 如果给定的n大于原字符串剩余的大小,则n等同于原字符串剩余的大小,即返回剩下所有的字符串;
  • 如果n未给定(n = -1),或者n<0,则也会返回position后的所有字符串;

QString QString::sliced(qsizetype pos, qsizetype n) const [since 6.0]

  • 作用和mid相同;
  • 除此之外还有1个重载函数,两个函数都是自Qt6.0之后新加的;
    • QString QString::sliced(qsizetype pos) const [since 6.0]
  • 注意,以下情况可能会出现不可预知(源码其实也是有做断言ASSERT的):
    • 如果pos超过原字符串的边界;
    • n小于0;
    • n + pos > size()
  • 该函数自Qt6.0后引入,目的是取消复杂的判断使得返回字符串更快;
remove*

共有9个remove系列的函数,返回值都是*this,也就是会更改原字符串的内容。

  1. QString &QString::remove(qsizetype position, qsizetype n)
    • 作用:删除源字符串从position开始,包括position的后n个字符
    • 如果position + n超出了原字符串的长度,则会把position后的字符全删掉;如果n<0则直接返回;
    • 如果position<0,则会从字符串最后开始删除,最后一位算-1,以此类推;
    • 注意:字符串中字符的删除不会释放实际预申请的空间,这点可以调用capacity()查看到,如果想释放多余的内存空间,可以在remove后使用squeeze()函数;
  2. QString &QString::remove(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive)
    • 作用:删除源字符串中出现的每一个ch字符/串
    • 除此之外还有3个重载函数
    • 同样的也不会释放预申请的空间,该函数等同于replace(str, "", cs)
    • 重载函数中同样也有使用正则表达式的形式;
  3. QString &QString::removeAt(qsizetype pos) [since 6.5]
    • 作用:删除pos所在位置的字符
    • 如果pos超出了原字符串的边界(pos<0 || pos >= size()),则不会进行任何操作;
    • 该函数返回的是*this
  4. QString &QString::removeFirst() [since 6.5]
    • 作用:删除原字符串的第一个字符
    • 如果原字符串为空,则不会发生任何事;
  5. template <typename Predicate> QString &QString::removeIf(Predicate pred) [since 6.1]
    • 从原字符串中删除所有pred返回为true的字符;
  6. QString &QString::removeLast() [since 6.5]
    • 作用:删除原字符串的最后一个字符
    • 如果原字符串为空,则不会发生任何事;
section

QString QString::section(QChar sep, qsizetype start, qsizetype end = -1, QString::SectionFlags flags = SectionDefault) const

作用:返回原字符串的一部分

  • 除此之外还有2个重载函数
  • section()函数可以用字符、字符串、正则表达式作为分隔符去得到子串,使用正则表达式会比前面两种方式慢得多;
  • 如果sep为空,则无论后面startend是多少,返回的都是一个空串;
  • startend都可以是负数,0代表第一个字符串,-1代表最后一个子串,-2代表倒数第二个子串,以此类推;
  • startend都是闭区间,[start, end],返回的子串会包含这两个;
  • end默认为-1,也就是说,如果没有指定,则会返回从start到原字符串最后;
  • 可以指定分割符的风格,例如flags = QString::SectionSkipEmpty,则会跳过分割出来的空串(详细例子里有);
  • 枚举enum QString::SectionFlag及含义(后面例子有详细用法):
    • QString::SectionDefault:默认值为0x0;
    • QString::SectionSkipEmpty:如果头尾有分隔符存在,则跳过头尾分割出来的空串;
    • QString::SectionIncludeLeadingSep:返回的子串包含前面的分隔符;
    • QString::SectionIncludeTrailingSep:返回的子串包含后面的分隔符;
    • QString::SectionCaseInsensitiveSeps:分隔符不区分大小写,默认区分大小写;
  • 默认风格:
    • 不会跳过空串,也就是说,如果sep在头和尾都有出现,则分割的子串至少有两个空串(头和尾各一个);
    • 如果startend是连续的,则最后的子串中间会有分隔符;
    • 默认返回的子串不会带头和尾的分隔符;
shrink_to_fit

void QString::shrink_to_fit()

  • 该函数功能和squeeze()完全一样,只是提供和STL兼容的写法;
simplified / trimmed

QString QString::simplified() const

作用:返回一个去掉开头和结尾的空字符,且把中间多个空字符替换为一个的原字符串的拷贝字符串

QString QString::trimmed() const

  • 只去掉开头和结尾的空白字符,中间空白字符不会变
squeeze

void QString::squeeze()

作用:提供一种微调QString内存的方法,让QStirng申请的内存空间压缩

truncate

void QString::truncate(qsizetype position)

作用:从包括position开始删除原字符串一直到最后为止

  • 如果position超出边界,则什么都不会发生;

  • 如果position是负数,则position等同于0,就是相当于全删完;

  • chop()的区别和演示:

  • QString str1_QS_t("qt for everything");
    QString str2_QS_t("qt for everything");
    str1_QS_t.chop(5); //"qt for every" size: 12 capacity: 17
    str2_QS_t.truncate(5); //"qt fo" size: 5 capacity: 17
    str2_QS_t.truncate(-5); //"" size: 0 capacity: 17
    

3.3

fill

QString &QString::fill(QChar ch, qsizetype size = -1)

作用:把字符串的每一个字符都更改为ch

  • 默认按照原来的字符串长度填充,如果指定长度,则按照指定长度填充;
  • 如果size小于0,则按照原来的字符串长度填充;
replace

该函数共有12种形式,其中11个重载函数,以下详细说几个常用的形式

  1. QString &QString::replace(qsizetype position, qsizetype n, const QString &after)

    • positon开始,使用字符串after,替换原字符串包含position位置共n个字符;
    • 如果n超过了剩余的原字符串的长度,则会把从position到原字符串末尾的字符全部替换为after
    • 如果n为0,则相当于在position的位置前面插入字符串after
    • 如果position为负数,则什么都不会发生,并不会像通常那样负数指的原字符串末尾;
    • 如果n为负数,则会出现问题,并不会在position位置增加字符串after
  2. QString &QString::replace(qsizetype position, qsizetype n, QChar after)

    • 同第一点的描述;
  3. QString &QString::replace(qsizetype position, qsizetype n, const QChar *unicode, qsizetype size)

    • 同第一点的描述;
  4. QString &QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

    • 会把原字符串中的所有before字符替换为after字符;
  5. QString &QString::replace(const QChar *before, qsizetype blen, const QChar *after, qsizetype alen, Qt::CaseSensitivity cs = Qt::CaseSensitive)

    • 可以指定替换和被替换的字符串的长度,不会造成重复替换
    • 如果blen小于before的长度,则按照beforeblen的长度来替换;如果大于,则不替换直接返回;
    • 如果alen小于after的长度,则按照afteralen的长度来替换;如果大于,则多余的使用空字符(u+0000)填充
  6. QString &QString::replace(QLatin1StringView before, QLatin1StringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

  7. QString &QString::replace(QLatin1StringView before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

  8. QString &QString::replace(const QString &before, QLatin1StringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

  9. QString &QString::replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

    • 顺序替换完成后,不会重新扫描字符串然后继续替换,例如:

    • QString equis = "xxxxxx";
      equis.replace("xx", "x"); // equis == "xxx"
      
  10. QString &QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

  11. QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)

  12. QString &QString::replace(const QRegularExpression &re, const QString &after)

    • 可以使用正则表达式查询需要被替换的字符串;

    • 常用的方式:可以使用\1、\2...等来代替前面正则表达式捕捉到的值,正则表达是里面需要用()来写子表达式(参考:正则表达式 – 语法);

    • 举个例子:

    • QString str4_QS_t("Qt qt qqt qqttqq");
      static QRegularExpression express_QRE_s("([^Q ]*)([t]+)([q]?)");
      //"Q() (q) (qq) (qqt)q"
      str4_QS_t.replace(express_QRE_s, QString("(\\1)"));
      str4_QS_t = "Qt qt qqt qqttqq";
      //"Q(t) (t) (t) (t)q"
      str4_QS_t.replace(express_QRE_s, QString("(\\2)"));
      str4_QS_t = "Qt qt qqt qqttqq";
      //"Q() () () (q)q"
      str4_QS_t.replace(express_QRE_s, QString("(\\3)"));
      str4_QS_t = "Qt qt qqt qqttqq";
      //"Q(\\4) (\\4) (\\4) (\\4)q"
      str4_QS_t.replace(express_QRE_s, QString("(\\4)"));
      str4_QS_t = "Qt qt qqt qqttqq";
      //"Q(t\\4) (qt\\4) (qqt\\4) (qqttq\\4)q"
      str4_QS_t.replace(express_QRE_s, QString("(\\1\\2\\3\\4)"));
      
reserve

void QString::reserve(qsizetype size)

作用:确保字符串中有size大小的空间

  • 如果能预先知道字符串大致要使用多少空间,建议使用该函数,因为可以避免多次重复申请空间而造成的内存碎片,提高整体性能;

  • 如果后续还要多次向字符串中添加,使用该函数预先估一个值也能避免添加操作的最后一次操作申请一个非常大的空间,具体可查看 QString的内存分配机制

  • 注意:使用reserve()函数预留内存并不会更改字符串本身的大小;

    • 如果reserve()的大小比字符串的大小大,在这种情况下访问超出字符串末尾边界会造成不可预知的行为;
    • 如果确实需要访问末尾边界后,可以使用resize()重新分配大小;
  • 测试的几种现象:

  • QString str1_QS_t;
    str1_QS_t.reserve(17); //17
    str1_QS_t.push_back("Qt");
    str1_QS_t.reserve(7); //17
    str1_QS_t.reserve(20); //20
    str1_QS_t.clear(); //0
    str1_QS_t.reserve(5); //5
    str1_QS_t = ""; //5
    str1_QS_t.reserve(3); //5
    
    str1_QS_t = "Qt For Everything";
    str1_QS_t.reserve(5); //17
    
  • 最长见的使用情况是:对于一个会往后面添加很多次字符的字符串,大致知道最后这个很长的字符串有多大,这个时候可以按照下面来使用。

  • QString result;
    qsizetype maxSize;
    
    result.reserve(maxSize);
    while (condition) {xxxx/*比如在这里添加文件数据流*/}
    result.squeeze(); //完成之后压缩大小
    
resize

void QString::resize(qsizetype size)

作用:重新设置该字符串的大小

  • 除此之外还有1个重载函数

  • 其实底层都会重新构造一个QString的DataPointer类,然后把数值按照给定的大小::memcpy()过去;

  • 如果size比原来的字符串大小要大,则后面多扩充的空间是没有初始化的;

  • 如果size比原来的字符串大小要小,则会删掉大于size的字符串;

  • QString s = "Hello world";
    s.resize(5);// s == "Hello"
    s.resize(8);// s == "Hello???"后面的字符是未初始化的
    
  • 通过resize()函数重设后的字符串,也有动态增长空间的功能;

  • 如果size为负,则为空串(isEmpty:true, isNull:false),跟clear()不同;

  • 还有一个重载函数可以设置重新设置大小后填充的字符:

    • void QString::resize(qsizetype newSize, QChar fillChar)
    • 该函数可以和leftJustified()类比使用:
  • QString str2_QS_t("Qt");
    str2_QS_t = str2_QS_t.leftJustified(10, u'Q'); //"QtQQQQQQQQ"
    str2_QS_t = "Qt";
    str2_QS_t.resize(10, u'T'); //"QtTTTTTTTT"
    

3.4

at

const QChar QString::at(qsizetype position) const
作用:返回指定位置的字符

  • 在不对字符进行修改的情况下建议使用at(),因为它不会发生深拷贝,比operator[]快。
back / front
  1. QChar QString::back() const
    作用:返回字符串最后的字符

    • 这里还有一个类似重载的函数可以修改最后的值:

      • QChar &QString::back()
      • 在Qt6以前是用QCharRef重载QChar来实现的,Qt6丢弃了QCharRef这个类。
    • 该函数兼容STL,建议不要对空字符串(isNull())使用,不然会出现未定义行为。

  2. QChar QString::front() const
    作用:返回字符串最前面的字符

    • 这里还有一个类似重载的函数可以修改最前面的值:

      • QChar &QString::front()
    • 其他描述参照back()

  3. Example:

    • QString str1_QS_t("peak");
      str1_QS_t.front() = 'b';
      str1_QS_t.back().setCell(0x74u);//after modified str1_QS_t == "beat"
      
capacity

qsizetype QString::capacity() const
作用:返回实际开辟的内存空间容量

  • 注意,无论静态(static)的字符串多大,返回结果都为0,也就是说该函数返回的是上的空间大小。
*compare

有两中关于字符串比较的函数,其中一个是基于数值比较,非常快;另一个是基于平台和地区比较,可读性较好,常用于界面显示的字符串比较;

static int QString::compare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
作用:比较两个字符串的大小

  • 除此之外还有8个重载函数,其中有4个静态函数;
  • 逐个字符进行比较,如果相等返回0,前小于后返回正的差值,前大雨后返回负的差值;
  • 区分大小写的比较完全基于字符的Unicode数值,并且非常快;
  • 注:区分大小写的比较可能会不按照期望的那样(因为按照Unicode编码数值进行比较的),所以当出现汉字、其他语言等字符串的比较可以使用静态函数:localeAwareCompare()

static int QString::localeAwareCompare(const QString &s1, const QString &s2)

作用:按照Locale设定的进行字符串比较

  • 除此之外还有3个重载函数,其中有1个静态函数,功能类似compare()函数;
  • 其中有2个重载函数是在Qt6.0之后引入的:
    • int QString::localeAwareCompare(QStringView other) const [since 6.0]
    • static int QString::localeAwareCompare(QStringView s1, QStringView s2) [since 6.0]
  • 关于比较的参考:Comparing Strings
constData

const QChar *QString::constData() const

作用:返回字符串中只读的原始数据

  • 注意,返回的指针只在字符串没有被修改时有效;
  • 注意,返回的字符串可能不是以’\0’结尾的,可以使用size()确定字符数组的长度;
contains

bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
作用:返回是否包含字符串str

  • 除此之外该函数还有4个重载函数
  • 其中有单独查询一个QChar的重载函数;
  • 还有一种重载函数可以用正则表达式:
  • bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const
  • 如果匹配成功并且rmatch不是nullptr,它还将匹配结果写入rmatch所指向的QRegularExpressionMatch对象。
count

qsizetype QString::count(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
作用:返回该字符串中出现字符或串str的次数

  • 除此之外还有3个重载函数
  • 其中有一个重载函数可以使用正则表达式,返回正则表达式匹配后的字符串出现的次数。
  • 其中有一个重载函数是Qt6.0之后出现的:
    • qsizetype QString::count(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const [since 6.0]
  • 注意:有一个同名的重载函数已经在Qt 6.4中废弃使用了;所以这里没有算在上面重载函数中;
data

QChar *QString::data()

作用:返回指向该字符串数据的指针,可以通过该指针访问和修改该字符串数据

  • 除此之外还有1个重载函数,作用和constData()一样;
  • 注意,返回的字符数组始终以’\0’结尾;
  • 只有当字符串没有被其他方式修改时,指针才有效;
  • 当使用指针修改字符串时(++[data] = ‘x’),会导致深拷贝的发生;
endsWith / startsWith

bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

作用:查询字符串是否以给出的字符/串结尾

  • 除此之外还有3个重载函数

bool QString::startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

作用:返回原字符串是否以s开始的

  • 除此之外还有3个重载函数
indexOf / lastIndexOf

qsizetype QString::indexOf(const QString &str, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

作用:返回指定字符串在该字符串中第一次出现的位置

  • 除此之外还有4个重载函数

  • 可以使用from指定从哪个位置开始查找,也可以指定大小写敏感,如果没有找到则返回-1

  • 如果from是负数,则代表从最后开始找,例如from = -1代表从最后一个字符开始找;

  • 重载函数中可以使用正则表达式;

  • Example:

    QString str1_QS_t("Reference by Taiga");
    QString str2_QS_t("re");
    qsizetype index_qst_t = str1_QS_t.indexOf(str2_QS_t);           //4
    index_qst_t = str1_QS_t.indexOf("Re", 1, Qt::CaseInsensitive);  //4
    index_qst_t = str1_QS_t.indexOf("ga", -1);                      //-1
    index_qst_t = str1_QS_t.indexOf("ga", -2);                      //16
    index_qst_t = str1_QS_t.indexOf(QChar('a'), -5);                //14
    
    QRegularExpressionMatch match_QREM_pt;
    static QRegularExpression expression_QRE_s("[aeiou]+");
    //index_qst_t:14    //match_QREM_pt.captured():"ai"
    index_qst_t = str1_QS_t.indexOf(expression_QRE_s, -5, &match_QREM_pt);
    expression_QRE_s.setPattern("e[^aeiou]");
    index_qst_t = str1_QS_t.indexOf(expression_QRE_s);              //1
    
  • 所有函数的返回值都是[[nodiscard]]

qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

作用:返回指定字符串在该字符串中最后出现的位置

  • 除此之外还有9个重载函数

  • from指定从该位置开始(包括该位置向前搜索最后一次出现的字符串,没找到则返回-1

  • 因为从最后搜索是包含指定位置的,所以当指定搜索的字符串为空串且使用默认搜索位置时,返回的是最后一位的后一位(具体例子有);

  • 5个重载函数是QT6之后引入的:

    • qsizetype QString::lastIndexOf(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const [since 6.3]
    • qsizetype QString::lastIndexOf(QLatin1StringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const [since 6.2]
    • qsizetype QString::lastIndexOf(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const [since 6.2]
    • qsizetype QString::lastIndexOf(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const [since 6.2]
    • qsizetype QString::lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const [since 6.2]
  • 同样也能用正则表达式,但是算法和查找字符串不太一样;由于正则表达式匹配算法的工作方式,这个函数实际上会从字符串的开始重复匹配,直到到达字符串的末尾。

  • 例子:

  • QString str1_QS_t("Reference by Taiga");
    qsizetype index_qst_t;
    index_qst_t = str1_QS_t.lastIndexOf("AI", Qt::CaseInsensitive); //14
    
    index_qst_t = str1_QS_t.lastIndexOf(QString("e")); //8
    index_qst_t = str1_QS_t.lastIndexOf(QString("e"), 0); //-1
    index_qst_t = str1_QS_t.lastIndexOf(QString("e"), -1); //8
    
    index_qst_t = str1_QS_t.lastIndexOf(QString("re"), 4); //4
    index_qst_t = str1_QS_t.lastIndexOf(QString("re"), 5); //4
    index_qst_t = str1_QS_t.lastIndexOf(QString("re"), 3, Qt::CaseInsensitive); //0
    
    index_qst_t = str1_QS_t.lastIndexOf(QString("")); //18
    index_qst_t = str1_QS_t.lastIndexOf(QString(""), -1); //17
    index_qst_t = str1_QS_t.lastIndexOf(QString(""), 0); //0
    
    static QRegularExpression expression_QRE_s("[eiou](g)?");
    QRegularExpressionMatch match_QREM_pt;
    index_qst_t = str1_QS_t.lastIndexOf(expression_QRE_s, &match_QREM_pt); //15 "ig"
    index_qst_t = str1_QS_t.lastIndexOf(expression_QRE_s, -3, &match_QREM_pt); //15 "ig"
    index_qst_t = str1_QS_t.lastIndexOf(expression_QRE_s, -4, &match_QREM_pt); //8 "e"
    
is*

6的判断字符串的函数;

  • 判空
    Qt makes a distinction between null strings and empty strings for historical reasons.

    • bool QString::isEmpty() const

      • 判断字符串是否是个空字符串,和isNull()有区别;
    • bool QString::isNull() const

      • 判断QString里面是否为空,和isEmpty()有区别;

      • QString().isEmpty();   // returns true
        QString("").isEmpty(); // returns true
        QString().isNull();    // returns true
        QString("").isNull();  // returns false
        
  • 判断大小写

    • bool QString::isLower() const
      • 注意:如果返回true并不代表该字符串不包含大写字符,因为某些大写字符并没有小写映射;
      • 通常用于判断标准英文字母的大小写;
      • 参考:Glossary::folding(unicode.org)
    • bool QString::isUpper() const
      • 判断是否为全大写字符串,参考isLower()
  • bool QString::isRightToLeft() const

  • bool QString::isValidUtf16() const

    • 验证是否包含有效的UTF-16编码数据;
    • 注意,该函数不会做额外的数据验证,仅仅是判断是否能以UTF-16解译;
    • 该函数默认主机字节序,在本函数字节序标记(BOM)没意义;
length / size

两个函数是一样的,都是返回字符串中字符的个数;

  • qsizetype QString::length() const
  • qsizetype QString::size() const
  • 注意:有一个同样功能的函数在Qt 6.4及以上版本被废弃使用了,所以这里不列出了(虽然为了向下兼容还是可以用的),如果在之前的旧的版本可以使用,但是还是建议使用length()/size()

3.5

arg

QString QString::arg(const QString &a, int fieldWidth = 0, QChar fillChar = u' ') const
作用:返回一个被格式控制字符替换后的新字符串

  • 除此之外还有14个重载函数

  • 可以指定额外填充的字符和方向,例如:

  • QString result_QS_t;
    QString padded_QS_t("lie");
    QChar fillChar_QC_t = u'e';
    //result_QS_t结果:"believe"
    result_QS_t = QString("be%1%2").arg(padded_QS_t).arg("ve");
    //result_QS_t结果:"belieeeevvvve"
    result_QS_t = QString("be%1%2").arg(padded_QS_t, -6, fillChar_QC_t).arg("ve", 5u, QChar::fromLatin1('v'));
    
  • asprintf()函数相比,该函数有以下有优点:

    • 不需要关心数字的顺序问题;
    • 数字可以重复代替;
  • //result_QS_t结果:"belielielieve"
    result_QS_t = QString("be%2%2%2%1").arg("ve").arg(padded_QS_t);
    
  • 关于arg()函数的规范用法说明:clazy/docs/checks/README-qstring-arg.md at 1.11 · KDE/clazy (github.com)

  • 其中还有一个模板重载函数:template <typename Args> QString QString::arg(Args &&... args) const

    • 用多个.arg()的方式会导致不必要的拷贝,因为该函数会返回一个拷贝的字符串(Returns a copy of this string);

    • 会有警告:Use multi-arg instead [clazy-qstring-arg]

    • 所以有多个替换的时候尽量用多参数来代替,例如:

    • //result_QS_t结果:"believe"
      result_QS_t = QString("be%1%2%3").arg(padded_QS_t, QChar('v'), "e"_L1);
      
  • 当填充为整数数字时:

    • 可以指定填充的进制(2~36),默认为10进制填充;

    • 如果填充的是intlong类型,且在10进制的情况下,还可以快捷指定定位符(例如,等),默认为当前使用语言和地区。

    • QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
      str = QString("%1 %L2 %L3")
              .arg(12345)
              .arg(12345)
              .arg(12345, 0, 16);//不是10进制则忽略
      // str == "12345 12,345 3039",这里的,就是定位符
      
  • 当填充的数字为实数时:

    • 可以用浮点数格式字符来控制显示格式,默认format'g'

    • 例如:

      double PI_d_t = 31415926.535897932384626;
      QString str_QS_t = QString(QStringLiteral("π:%1")).arg(PI_d_t, 0, 'e', 4);
      //结果:"π:3.1416e+07"
      
      • format格式字符的含义precision含义
        ‘e’科学计数法,如3.14e+2基数的小数点后的有效位数
        ‘E’科学计数法,如3.14E-3基数的小数点后的有效位数
        ‘f’自然计数法,如3.14-3.14小数点后的有效位数
        ‘g’使用’e’或’f’,哪种简洁用哪种小数点前后的数字位数之和
        ‘G’使用’E’或’f’,哪种简洁用哪种小数点前后的数字位数之和
asprintf / vasprintf

有两个使用格式控制字符构造Qstring的静态函数

static QString QString::asprintf(const char *cformat, ...)
作用:根据格式化字符串和参数列表安全的构建一个字符串

  • 该静态函数用于构造格式化输出各种数据的字符串,类似于标准C语言中的printf(),可以使用转义序列(escape sequence),也可以指定数据宽度和小数位数等。

  • 注意,虽然cformat格式化字符串中支持汉字,但是使用%s替换cformat中的字符串只能用UTF-8编码的字符串,并且只能是char *类型。例如:

  • QString strReplaced_QS_t("世界");
    QString strResult_QS_t(QString::asprintf("Hello, World.(你好,%s。)", "世界")); //错误的,这样写跟源程序代码编码有关,如果源文件编码为UTF-8则能显示否则显示乱码
    strResult_QS_t = QString::asprintf("Hello, World.(你好,%s。)", strReplaced_QS_t.toLocal8Bit().data()); //错误的,会得到乱码
    strResult_QS_t = QString::asprintf("Hello, World.(你好,%s。)", strReplaced_QS_t.data()); //错误的,会得到乱码
    
    strResult_QS_t = QString::asprintf("hello, world %.10f", 3.1415); //正确的,结果为"hello, world 3.1415000000"
    
  • 关于转义序列:

    • %lcchar16_t或者ushort类型,或者QChar::unicode()的返回值也行;
    • %ls:以字符'\0'结尾的char16_t或者ushort类型的指针或地址,或者QString::utf16()的返回值也行;
    • 这两个与标准C++库中的printf()不一致,标准C++库定义%lc输出wchar_t类型,%ls输出wchar_t *类型,还可能在sizeof(wchar_t)不是16位的平台上产生编译器警告。
  • 官方的建议不要使用asprintf()函数:

    • We do not recommend using QString::asprintf() in new Qt code. Instead, consider using QTextStream or arg(), both of which support Unicode strings seamlessly and are type-safe.

    • Here is an example that uses QTextStream:

    • QString result;
      QTextStream(&result) << "pi = " << 3.14;
      // result == "pi = 3.14"
      
  • 对于需要多国翻译的字符串,建议使用arg()函数,因为被替代的序列也可以被Qt的翻译器(类似tr())所控制。

static QString QString::vasprintf(const char *cformat, va_list ap)

  • 该函数作用和asprintf()一致,但是使用了va_list宏来代替了可变参数列表...
  • 关于格式控制字符和asprintf()函数完全一致;
  • 具体参考:std::va_list - cppreference.com
  • 注意:该函数不会清空va_list可变参数列表,所以需要在外面手动清空ap如:va_end(ap)
number

static QString QString::number(long n, int base = 10)

作用:返回指定进制和数字的数值一致的字符串

  • 除此之外还有6个重载函数,全部都是静态函数
  • 基本常用的格式都包含进去了,对于浮点型还能指定格式精度,参考arg()函数的格式表;
  • 例子:QString t = QString::number(a, 16).toUpper(); //t == "3F"
set*

共有4种把其他类型转变为QString的方法。

  1. QString &QString::setNum(int n, int base = 10)
    作用:把数字n转变为字符串
    • 除此之外还有9个重载函数
    • 该函数返回的字符串默认用QLocale::C标准(English/United States),如果需要返回本地区域的字符串,可以用QLocale::toString()
    • 注意返回的是*this指针,会修改源字符串的值;
    • 也可以把实数设置为字符串,可以设置格式控制字符和精度;参考number()函数;
  2. QString &QString::setRawData(const QChar *unicode, qsizetype size)
    • 使用QChar数组设置字符串,必须保证源数据不会被修改或删除;
    • 设置的QString不是用源数据拷贝生成的,一旦需要修改QString的内容,则会发生深拷贝;
  3. QString &QString::setUnicode(const QChar *unicode, qsizetype size)
    • setRawData()函数不同的是该函数会把源数据拷贝一份;
    • **注意:**如果unicode是个空串,设置的QString也会按照size来设置空间大小;
  4. QString &QString::setUtf16(const ushort *unicode, qsizetype size)
    • 设置该字符串为使用UTF-16标准的字符串,设置大小为size
    • 注意:如果unicode是个空串,设置的QString也会按照size来设置空间大小;
    • 注意:该函数和fromUtf16()不一样,该函数不考虑BOM和可能出现不同的字节顺序;
split

QStringList QString::split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

作用:返回以sep分割但不包括的子字符串列表

  • 除此之外还有2个重载函数

  • 如果没有找到分隔符,则会返回一个包含一个字符串的列表;

  • 可以指定大小写敏感和子字符串列表格式;

    • Qt::KeepEmptyParts:如果子字符串有空,则保留到列表中;
    • Qt::SkipEmptyParts:如果子字符串有空,则不会保留到列表中;
  • 注意:如果sep为空,则会返回一个前后都为空串,中间是每一个QString中的字符构造的字符串;其实也就相当于原始字符串中每个字符中间(包含头尾)都有一个空串,(详细例子有);

  • 同样的,也可以使用正则表达式作为sep,可以实现很多方便的功能;

  • 例子:

  • 
    QString str1_QS_t("qt for,everything reference,");
    QString str2_QS_t("Q t");
    QStringList result_QSL_t;
    result_QSL_t = str1_QS_t.split(";"); //["qt for,everything reference,"]
    result_QSL_t = str1_QS_t.split(","); //["qt for", "everything reference", ""]
    result_QSL_t = str1_QS_t.split(",", Qt::SkipEmptyParts); //["qt for", "everything reference"]
    result_QSL_t = str2_QS_t.split(QString(), Qt::KeepEmptyParts); //["", "Q", " ", "t", ""]
    result_QSL_t = str2_QS_t.split(QString(), Qt::SkipEmptyParts); //["Q", " ", "t"]
    const QRegularExpression expr_QRE_c("\\b[^a-z^A-Z]");
    result_QSL_t = str1_QS_t.split(expr_QRE_c, Qt::SkipEmptyParts); //["qt", "for", "everything", "reference"]
    
swap

void QString::swap(QString &other)

作用:和其他字符串交换

  • 该函数的字符串交换操作非常快(其实就是交换数据),并且从来不会失败;
to*

QString提供了一系列的转换其他类型的函数,一共25

OS-String

2个转换为苹果API中String的函数,仅在macOS和iOS系统下可用

  1. CFStringRef QString::toCFString() const
    • 转换后调用者需要去主动释放该字符串内容;
    • 参考fromCFString()
  2. NSString *QString::toNSString() const
    • 转换的NSString调用者不需要主动释放
    • 参考fromNSString()
Case

3个大小写转换相关的函数

  1. QString QString::toCaseFolded() const
    • 通常会转换为小写字符;
  2. QString QString::toLower() const
    • 将原字符串转换为小写字符然后返回一个拷贝的字符串;
    • 使用的是标准'C' locale,如果要转换为本地地区的小写,可以使用QLocale::toLower()
  3. QString QString::toUpper() const
    • 转换为大写形式,对于某些Unicode字符可能只有大写没有小写;
number

10个转换为数字数值相关的函数

  1. double QString::toDouble(bool *ok = nullptr) const

    • 如果转换溢出上边界,则返回无穷大,如果转换失败(例如溢出下边界),则会返回0.0

    • 关于无穷大QT也有个宏定义(Q_INFINITY),是基于ISO C99 macro INFINITY的;参考:Infinity and NaN (The GNU C Library)

    • 可以设置是否成功转换的标志ok

    • 被转换的字符串内容只能包含有效的数字字符,包括正负号、科学记数法中使用的字符e和小数点。包含单位($等)或附加字符会导致转换错误。

    • 该函数的转换是默认用QLocale::C标准(A simplified English locale);

      • 如果使用其他国家地区的数字转换请用QLocale::toDouble()函数;

      • 例如:

      • double d;
        d = QString( "1234,56" ).toDouble(&ok); // ok == false
        d = QString( "1234.56" ).toDouble(&ok); // ok == true, d == 1234.56
        
        QLocale german(QLocale::German);
        d = german.toDouble("1234,56", &ok);  // ok == true,  d == 1234.56
        d = german.toDouble("1.234,56", &ok); // ok == true,  d == 1234.56
        d = german.toDouble("1234.56", &ok);  // ok == false, d == 0
        d = german.toDouble("1.234", &ok);    // ok == true,  d == 1234.0
        
    • 因为历史原因,该函数也不会处理千位分隔符,如果需要带分隔符一起转换,可以使用QLocale::toDouble()函数;

      • 例如:

      • d = QString( "1,234,567.89" ).toDouble(&ok); // ok == false
        
        QLocale c(QLocale::C);
        d = c.toDouble("1,234.56", &ok); // ok == true,  d == 1234.56
        
    • 注意:该函数还会忽略字符串首尾的空白符;

  2. float QString::toFloat(bool *ok = nullptr) const

    • 参考toDouble()
  3. int QString::toInt(bool *ok = nullptr, int base = 10) const

    • 将字符串按照指定的进制转换为int类型数据,可以传递转换成功与否标志;
    • 可指定进制在2~36之间,默认为10进制;
    • 如果失败,ok设为false且返回0
    • 注意:如果指定base0,则该字符串会参考C语言的习惯转换,例如:
      • 0x开头的字符串会被认为是16进制的;
      • 0b开头的字符串会被认为是2进制的(这个是自从Qt6.4之后才支持的);
      • 0开头的字符串会被认为是8进制的;
      • 其他则默认为10进制的;
    • 同样的,该函数默认使用QLocale::C标准,如果需要用本地格式转换可以用QLocale::toInt()函数;
    • 注意:该函数会忽略前导空格和尾随空格;
  4. long QString::toLong(bool *ok = nullptr, int base = 10) const

    • 参考toInt()
  5. qlonglong QString::toLongLong(bool *ok = nullptr, int base = 10) const

    • 参考toInt()
  6. short QString::toShort(bool *ok = nullptr, int base = 10) const

    • 参考toInt()
  7. uint QString::toUInt(bool *ok = nullptr, int base = 10) const

    • 参考toInt()
    • 如果有负数,则也会返回失败,返回值为0;
  8. ulong QString::toULong(bool *ok = nullptr, int base = 10) const

    • 参考toUInt()
  9. qulonglong QString::toULongLong(bool *ok = nullptr, int base = 10) const

    • 参考toUInt()
  10. ushort QString::toUShort(bool *ok = nullptr, int base = 10) const

    • 参考toUInt()
HTML

1个转换为HTML语言格式的函数

  1. QString QString::toHtmlEscaped() const

    • 作用:该函数会把纯文本字符串转换为HTML字符串

    • 会把< > & "等符号用HTML的方式代替;例如:

    • QString plain = "#include <QtCore>"
      QString html = plain.toHtmlEscaped();
      // html == "#include &lt;QtCore&gt;"
      
8-bit

3个转换为8bit字符串相关的函数

  1. QByteArray QString::toLatin1() const
    • 将源字符串转换为Latin1字符集的字符串;
    • 如果字符串包含非Latin1字符,则返回的字节数组中对应的位置可能会用'?'来代替;
  2. QByteArray QString::toLocal8Bit() const
    • 将源字符串转换为本地8bit的字符数组;
    • 如果是在Unix系统上,该函数相当于toUtf8(),如果是在Windows系统上,则按照系统正在使用的字符集转换;
    • 如果源字符串中有不是8-bit编码的字符,那么转换到字符数组中这些字符可能不显示或者用其他字符代替了;
  3. QByteArray QString::toUtf8() const
    • 将源字符串转换为UTF-8字符集字符串;
    • UTF-8是Unicode编解码器,可以表示Unicode字符串(如QString)中的所有字符。
std*

4个转换为标准std字符串相关的函数

  1. std::string QString::toStdString() const
    • 将原字符串转换为标准的字符串std::string
    • 因为QString是Unicode编码的,所以会用toUtf8()函数转为8-bit的字符串;
    • 该函数常用于将QSting传递出去然后用标准字符串接收;
  2. std::u16string QString::toStdU16String() const
    • 将原字符串转为标准字符串std::u16string
    • 其中的Unicode编码源数据和utf16()函数返回的一致;
  3. std::u32string QString::toStdU32String() const
    • 将原字符串转为标准字符串std::u32string
    • 其中的Unicode编码源数据和toUcs4()函数返回的一致;
  4. std::wstring QString::toStdWString() const
    • 将原字符串转为标准字符串std::wstring,即是宽字符串类型;
    • 补充说明:在类型wchar_t2字节的平台(例如 windows)上使用的是utf16编码,类型wchar_t4字节的平台(大多数Unix系统)上使用的是ucs4编码。
UCS4

1个转换为UCS4标准的字符串函数

  1. QList<uint> QString::toUcs4() const
    • 转换为UCS-4/UTF-32标准的字符列表;
    • 返回值是一个QList
    • 补充说明:
      • UCS-4是Unicode编解码器,因此它是无损的;
      • 该字符串中的所有字符将用UCS-4进行编码;
      • 如果出现任何不合法的字符,则会用QChar::ReplacementCharacter来代替,也就是U+FFFD(0xfffd)详细描述:enum QChar::SpecialCharacter
    • 注意:转换后的字符串(列表)不会以'\0'结尾;
    • 可以参考fromUcs4()函数,但是表示UCS4的类型不太一样;
wchar_t

1个转换为C++标准中wchar_t类型的字符串函数

  1. qsizetype QString::toWCharArray(wchar_t *array) const
    • 转换后的数组arraywchar_t2字节的平台(例如windows)上用UTF-16编码,在wchar_t4字节的平台(大多数Unix系统)上用UCS-4编码。
    • 注意:传入的数组array必须事先就分配好足够的空间,可以使用该字符串的length()来分配空间,这样空间肯定是足够的;
    • 该函数会返回转换后的数组array的实际长度;
    • 该函数不会在末尾对数组array追加空字符(‘\0’);
unicode

const QChar *QString::unicode() const

作用:返回源字符串的Unicode编码源数据

  • 返回的指针在源字符串未被修改前一直有效;
  • 注意:返回的字符串数据可能不会以'\0'结尾,请使用size()函数来确定数组的长度;
utf16

const ushort *QString::utf16() const

作用:将源字符串以’\0’结尾的无符号短整类型返回

  • 返回的指针在源字符串未被修改前一直有效;
  • 返回的源数据一定会以'\0'结尾;
  • 返回的字符串按主机字节顺序(host byte order)排列;

3.6

fromCFString / NSString
  1. static QString QString::fromCFString(CFStringRef string)
    作用:从苹果系统API中定义的常量字符串CFStringRef类获得一个QString

  2. static QString QString::fromNSString(const NSString *string)
    作用:从苹果系统API中定义的Unicode字符串NSString类构造一个QString

fromLatin1

static QString QString::fromLatin1(const char *str, qsizetype size)

作用:从Latin1字符集字符串获得长度为size的QString

  • 除此之外还有2个重载函数
  • 该静态函数构造字符串的长度是从最开始一直到长度为size为止;
  • 如果size为负数,则会按照strlen(str)来代替;
  • 如果size大于字符串本身的长度,会按照设置的size构造,但是构造的字符串大于strlen(str)的字符是不确定的;
  • 其中有1个重载函数是Qt6.0之后引入的
    • static QString QString::fromLatin1(QByteArrayView str) [since 6.0]
    • str中所有的'\0'字符都会转化为Unicode的空字符(U+0000);
  • 其中还有1个重载函数是在Qt6.0之后有所改动:
    • static QString QString::fromLatin1(const QByteArray &str)
    • str中所有的'\0'字符都会转化为Unicode的空字符(U+0000),这点在Qt5中的处理方式不一样;
fromLocal8Bit

static QString QString::fromLocal8Bit(const char *str, qsizetype size)

作用:从8-bit字符串获得长度为size的QString字符串

  • 除此之外还有2个重载函数
  • 该静态函数和fromLatin1()一样有1个是QT6.0之后引入的,有1个是QT6.0之后修改过的;
  • Unix系统上,该函数相当于fromUtf8(),在Windows系统上,会根据源文件的编码格式判断,如果是UTF-8编码格式,则直接用字符串常量会显示乱码。
fromRawData

static QString QString::fromRawData(const QChar *unicode, qsizetype size)

作用:使用原始的unicode数据构造一个QString

  • 构造的QString是没有通过深拷贝的,也就是说,如果原始数据修改或删除了,那么构造的QString也没有意义;

  • 该函数可以用来读写二进制Unicode字符串文件,如果不需要修改文件内容,但为了方便又要用到QString的一些查询相关的接口,就可以使用这种方法构造一个QString

  • 如果修改或拷贝构造出来的字符串,则会导致深拷贝的发生,可以参考QString的隐式共享

  • 该静态函数构造的QString字符串常常被用来只读和查询,因为这样非常快;

  • 例如,利用正则表达式匹配内存中的字符串:

  • QString str1_QS_t;
    //QT6以上不再支持隐式转换
    QChar unicode_QC_t[] = {
        (QChar)0x0071u, (QChar)0x0074u, (QChar)0x0020u,
        (QChar)0x0066u, (QChar)0x006fu, (QChar)0x0072u,
        (QChar)0x0020u, (QChar)0x0065u, (QChar)0x0076u,
        (QChar)0x0065u, (QChar)0x0072u, (QChar)0x0079u,
        (QChar)0x0074u, (QChar)0x0068u, (QChar)0x0069u,
        (QChar)0x006eu, (QChar)0x0067u
    };
    qsizetype size_qst_t = sizeof(unicode_QC_t) / sizeof(QChar);
    str1_QS_t = QString::fromRawData(unicode_QC_t, size_qst_t); //str1_QS_t === "qt for everything"
    static QRegularExpression pattern_QRE_s("\u0020");
    if (str1_QS_t.contains(pattern_QRE_s)) {
        qDebug() << "matched";
    }
    
  • 如果原始数据被删除或者修改了,则不能保证QString更改,这样做危险!

  • QChar *unicode_QC_p_t = new QChar[2];
    unicode_QC_p_t[0] = (QChar)0x0071u, unicode_QC_p_t[1] = (QChar)0x0074u;
    str2_QS_t = QString::fromRawData(unicode_QC_p_t, 2);
    qDebug() << "before deleted:" << str2_QS_t;
    delete[] unicode_QC_p_t; //don't do this;
    unicode_QC_p_t = Q_NULLPTR;
    qDebug() << "after deleted:" << str2_QS_t;
    
  • 注意:如果原始数据最后不是以’\0’结尾,则创建的字符串也不会以’\0’结尾;

    • 如果调用unicode()函数就不会返回一个以’\0’结尾的字符串;
    • 如果调用utf16()函数则会发生深拷贝,然后返回以’\0’结尾的字符串;
fromStd*

4个从C++标准字符串拷贝构造的字符串接口:

  • static QString QString::fromStdString(const std::string &str)
  • static QString QString::fromStdU16String(const std::u16string &str)
  • static QString QString::fromStdU32String(const std::u32string &str)
  • static QString QString::fromStdWString(const std::wstring &str)
  • 以上函数都会返回一个源数据的拷贝副本;
fromUcs/Utf*

3个静态函数从ISO-10646标准字符协议中构造QString

  • static QString QString::fromUcs4(const char32_t *unicode, qsizetype size = -1)
  • static QString QString::fromUtf8(const char *str, qsizetype size)
    • 除此之外还有4个重载函数
    • 其中有3个重载函数是在Qt6.0之后引入的:
      • static QString QString::fromUtf8(QByteArrayView str) [since 6.0]
      • static QString QString::fromUtf8(const char8_t *str) [since 6.1]
        • This overload is only available when compiling in C++20 mode.
      • static QString QString::fromUtf8(const char8_t *str, qsizetype size) [since 6.0]
        • This overload is only available when compiling in C++20 mode.
  • static QString QString::fromUtf16(const char16_t *unicode, qsizetype size = -1)
    • 该函数会检查字节序标记Byte Order Mark),如果没有,则会用主机字节序
    • 与其他Unicode转换相比,此函数速度较慢,该函数会深拷贝一份unicode数据;
  • 在以上函数中,某些函数如果没有指定字符串的大小,则都需要指定字符串结尾的符号;
  • 在以上函数中,某些函数有些函数如果size小于0,则会使用strlen(str)代替size
  • 在以上函数中,如果源数据更改或者删除,则会发生深拷贝,参考1.2 QString的隐式共享
fromWCharArray

static QString QString::fromWCharArray(const wchar_t *string, qsizetype size = -1)

作用:根据数据的格式自动判断编码并拷贝构造一个QString

  • 具体哪种编码方式得看sizeof(wchar_t)
    • 如果为4字节,则string被解释为UCS-4
    • 如果为2字节,则string被解释为UTF-16
  • 如果size未指定或者小于0,则需要字符串末尾有’\0’;
normalized

QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersion version = QChar::Unicode_Unassigned) const

作用:根据给定的Unicode标准,返回用该标准规范化的字符串

4. 关于QString的宏

4.1 QStringLiteral

  • QStringLiteral(str)宏的作用可以在编译期间通过指定的常量字符串str构建一个QString;

  • 这样就不用在运行期间创建临时的QString,而且通过这个宏生成的QString会被存储在已编译的对象文件(.obj/.o文件)的只读片段中;

  • 例如:

  • //这是传入某个形参为只读的QString引用的函数
    void thisIsFunction(const QString &str) {
        xxxxx;
    }
    
    bool otherFunction() {
    	//1:
        if (thisIsFunction("abcde...中间很长很长...xyz")) {
            xxxxxx;
        }
        //2:
        if (thisIsFunction(QStringLiteral("abcde...中间很长很长...xyz"))) {
            xxxxxx;
        }
    }
    
  • 第一种写法会在运行的时候使用这一串原始字符串(字符串在常量区)生成一个QString,这可能消耗内存和时间,因为它涉及到内存分配和将数据复制/转换为QString的内部编码;

  • 第二种写法QString的内部数据将在编译时生成; 在运行时不会发生任何转换或分配。

  • 使用QStringLiteral宏来代替双引号的纯C++字符串,可以显著加快从编译时已知的数据创建QString实例的速度。

  • 其实源码也有体现:

  • #define QT_UNICODE_LITERAL(str) u"" str
    
    #define QStringLiteral(str) \
        (QString(QtPrivate::qMakeStringPrivate(QT_UNICODE_LITERAL(str)))) \
        /**/
    
  • 注释:有些编译器对包含US-ASCII字符集之外的字符的字符串进行编码时存在 bug。在这些情况下,确保字符串的前缀是u,除此之外就不需要带u

  • 可以参考QByteArrayLiteral也是同样的原理;

Extensibility(扩展)

  1. 还有个自定义字面量后缀和该宏类似;
  • QString operator""_s(const char16_t *str, size_t size) [since 6.4]
  • QString是在编译时创建的,生成的字符串数据存储在已编译对象文件的只读段中。
  • 重复的文字可能具有相同的只读内存
  • 这个功能可以与QStringLiteral互换,但是当代码中出现许多字符串文字时可以节省输入。

关于一些类似的用法请参考:

  1. 可以用QLatin1StringView避免通过常量字符串构造出QString
  • 其实如果避免构造出一个QString(因为相比消耗大),可以用QLatin1StringView,它只是const char*的一个非常薄的包装器,不会有额外的开销;

  • 如果强迫症或者内存优化爱好者(比如我)可以经常使用,因为自从Qt6后大多数都提供了QLation1StringView的重载,可以极度减少开销优化内存利用空间;

  • Example:

  • if (thisIsAString_QS_m == "taiga") { //通过const char*构造QString
        if (thisIsAString_QS_m == "taiga"_L1) { //没有额外开销
            xxxxx;
        }
    }
    
  • 这样就避免了通过常量字符串构造出QString而占用额外开销了;

4.2 RestrictCast To/From

QString提供了3个限制关于QString字符/字符串的自动转换的宏,保证类型安全

QT_NO_CAST_FROM_ASCII
  • 描述:

    • 禁用从8-bit字符串(char *)到QString(Unicode)的自动转换;
    • 禁用从8-bit字符类型(charunsigned char)到QChar的自动转换;
  • 其实也就是禁用隐式的自动转换,优化对程序员来说透明(transparency)的一些东西;

  • 例如:

  • //transparency
    if (str == "auto" || str == "extern" || str == "static" || str == "register") {
        xxxxx;
    }
    
    //opacity
    if (str == "auto"_L1 || str == "extern"_L1 || str == "static"_L1 || str == "register"_L1 {
        xxxxx;
    }
    
QT_NO_CAST_TO_ASCII
  • 禁用从QString到8-bit字符串(char *)的自动转换;
  • 同理参考QT_NO_CAST_FROM_ASCII
QT_RESTRICTED_CAST_FROM_ASCII
  • 禁用大多数源字符串8-bit数据QString(Unicode)的自动转换;
  • 但允许下面这样的自动转换 ;
    • 构造字符:QChar(char)
    • 以常量引用数组方式构造字符串:QString(const char (&ch)[N])
    • 重载=操作符:QString::operator=(const char (&ch)[N])
  • 如果用这个宏,则既能保证像QT_NO_CAST_FROM_ASCII大多是都禁掉保证类型安全,又不需要用户代码用QLatin1CharQLatin1StringView或类似的方法包装字符和字符串文字。
  • 其实就是更方便使用,例如上面的例子如果全禁了虽然不透明,但是不方便使用;
  • 注释:Using this macro together with source strings outside the 7-bit range, non-literals, or literals with embedded NUL characters is undefined.

4.3 Printable

3个用于临时将QString转换为C/C++风格的字符串

注意

  • 返回的指针都是临时指向源字符串的,仅在当前语句块内有效;

    • 不能用于浅拷贝或者语句块外使用;

    • 例如:

    • QString str1_QS_t("abcd");
      //这里会有警告:Returning data of temporary QByteArray
      auto str2_c_tP = qPrintable(str1_QS_t);
      qDebug() << "1:" << str2_c_tP; //1: 错误的,该指针指向未知空间
      qDebug() << "2:" << qPrintable(str1_QS_t); //2: abcd
      
  • 在多线程中,由于多线程可能会同时访问同一个字符串,因此需要注意使用临时指针的线程安全问题。

  • 这三个宏也加入到<QtGlobal>头文件中了,可以全局使用;

qPrintable
  • const char *qPrintable(const QString &str)
  • 返回一个临时的指向源字符串数据的指针,等同于str.toLocal8Bit().constData()
  • 可以在qDebug(),qInfo(), qWarning(), qCritical(), qFatal()等用%s格式控制字符所需求UTF-8编码的时候使用;
  • 注意该宏转换出来的字符串是用本地的8-bit编码,如果需要记录字符串可以使用qUtf8Printable宏;
qUtf16Printable
  • const wchar_t *qUtf16Printable(const QString &str)

  • 将str作为const ushort *返回,但将其转换为const wchar *以避免警告;

  • 该宏相当于str.utf16()加上一些类型转换;

  • 基本上该宏唯一的作用就是在QString::asprintf()中使用%ls的时候转换一下;

  • 注意:该宏返回的不是一个严格合法的const wchar*

  • 同样返回的也是临时指针,用法:

  • qWarning("%ls: %ls", qUtf16Printable(key), qUtf16Printable(value));
    
qUtf8Printable
  • const char *qUtf8Printable(const QString &str)
  • 参考qPrintable宏,该宏等同于str.toUtf8().constData()

该文章的参考链接:

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Taiga_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值