Qt开发总结(6)——QString类

本篇将单独总结QString类。相比于C++ Std中的string来说,QString要好用的多。QString用来存储和处理字符串,其采用的是Unicode码,每个字符是一个16位的QChar(不是8位的char),所以QString同样可以处理中文字符,而且一个汉字算作一个字符。同时,QString应用了隐式共享以减少内存的使用,避免不必要的内存拷贝。

初始化

最简单和常见的QString初始化方法就是直接用const char *赋值:

QString str = "hello";     
QString str("hello");         //str的size是5

也可以用QChar数组初始化,这实际上是从QChar到QString的一个深度拷贝(可参见拷贝构造函数):

static const QChar data[4] = { 0x0055, 0x006e, 0x10e3, 0x03a3 };
QString str(data, 4);

QString的本质也是一种容器(参见上篇笔记),这使得它也可以用list的方式获取下标并进行赋值:

QString str;
str.resize(4);
str[0] = QChar('U');
str[1] = QChar('n');
str[2] = QChar(0x10e3);
str[3] = QChar(0x03a3);

QString str;
for (int i = 0; i < str.size(); ++i) {
    if (str.at(i) >= QChar('a') && str.at(i) <= QChar('f')) //用at获取值
        qDebug() << "Found character in range [a-f]";
}

特别的,at()函数要比取下标符号[]更快,因此它不会进行深拷贝。可以用 left(), right(), 或者mid()函数来一次性获取多个字符,他们的速度也是很快的。这些操作实际上就是容器中列表的操作。

使用QString

QString提供了基本的函数来修改数据: append(), prepend(), insert(), replace(), and remove(). 比如: 

  QString str = "and";
  str.prepend("rock ");     // str == "rock and"
  str.append(" roll");        // str == "rock and roll"
  str.replace(5, 3, "&");   // str == "rock & roll"

一个常见的需求是去掉字符串中的空格,则可以用trimmed()来去掉字符串首尾的空格,用simplified()将中间连续的空格用一个空格替换,并去掉字符串首尾的空格。 

QString str = "  Are you    OK?   ", str1;
str1 = str.trimmed();     // str1 == "Are you    OK? "
str1 = str. simplified ();     // str1 == "Are you OK? "

如果要获取字符串中某个字符所在位置,可以用indexOf() or lastIndexOf()函数。前者是记录某字符串从前端数所在的位置,后者是从后端数所在的位置。其参数第一个待寻找的字符串,第二个是开始找的起始位置,默认为0,返回值是位置。如果找不到则返回-1.下面的代码将找到所有的<b>。 

  QString str = "We must be <b>bold</b>, very <b>bold</b>";
  int j = 0;
  while ((j = str.indexOf("<b>", j)) != -1) {
      qDebug() << "Found <b> tag at index position" << j;
      ++j;
  }

QString 提供了很多函数来数字转换为字符串或将字符串转换为数字。如 arg(),setNum() ,number(), toInt(), toDouble()等等。

arg()函数用以将多个数字或字符串拼接起来,像是printf。它可以转换所有的数字类型和字符串类型。

int i;           // current file's number
int total;       // number of files to process
QString fileName;    // current file's name
QString status = QString("Processing file %1 of %2: %3")
                  .arg(i).arg(total).arg(fileName);

setnum()默认以十进制的形式转换为字符串:

QString str;
str.setNum(1234);       // str == "1234"

number用以转换数字到字符串,可指定进制,默认为10进制:

long a = 63;
QString s = QString::number(a, 16);             // s == "3f"

toInt和toDouble函数用以将字符串转化为数字:

QString str = "FF";
bool ok;
int hex = str.toInt(&ok, 16);       // hex == 255, ok == true
int dec = str.toInt(&ok, 10);       // dec == 0, ok == false

toUpper() or toLower()函数将字符串中的字母进行大小写转换。

QString str = "TeXt";
str = str.toUpper();        // str == "TEXT"
str = "The Qt PROJECT";
str = str.toLower();        // str == "the qt project"

可以用split函数将字符串分割为若干个子字符串,并由QStringList保存。或者用join函数将若干字符串组合为一个字符串。

QString str = "a,,b,c";
QStringList list1 = str.split(',');
// list1: [ "a", "", "b", "c" ]
QStringList list2 = str.split(',', QString::SkipEmptyParts);
// list2: [ "a", "b", "c" ]

因为一些历史原因,判断一个QString是NULL还是Empty,是两种不同的方法:一个NULL QString 是已经用0执行了默认构造函数, Empty意思是QString的长度为0.所以,一个NULL string肯定是empty的,但一个empty string不一定是null string。 

  QString().isNull();               // returns true
  QString().isEmpty();              // returns true

  QString("").isNull();             // returns false
  QString("").isEmpty();            // returns true

  QString("abc").isNull();          // returns false
  QString("abc").isEmpty();         // returns false

查询QString数据

如果想判断QString是否以某个字符串开头或者结尾的,可以用startsWith() or endsWith()函数,其返回值为bool。如果想判断字符串其中是否包含某字符串,可以用contains()函数;如果想统计该字符串出现的次数可以用count()函数。

  QString str = "Bananas";
  str.startsWith("Ban");     // returns true
  str.startsWith("Car");     // returns false

  QString str = "Peter Pan";
  str.contains("peter", Qt::CaseInsensitive);    // returns true

  QString str = "banana and panama";
  str.count(QRegExp("a[nm]a"));    // returns 4

QString可以用重定义的operator<(), operator<=(), operator==(), operator>=()符号进行比较判断。这些重写的方法在执行时是非常快的。

可以通过调用data() or constData()来获取一个字符串的指针。该指针指向第一个QChar,这就像回到的最初char *。

  QString str = "Hello world";
  QChar *data = str.data();
  while (!data->isNull()) {
      qDebug() << data->unicode();
      ++data;
  }

字符转换

在字符处理是经常遇到8位字符和Unicode之间的转换。QString 提供了三个函数来返回一个const char * :QByteArray: toUtf8(), toLatin1(), and toLocal8Bit().

  • toLatin1() 返回一个 Latin-1 (ISO 8859-1) 8位编码字符串.
  • toUtf8() 返回一个 UTF-8编码8-bit 字符串. UTF-8 是一个f US-ASCII (ANSI X3.4-1986) 的超级集合,提供了全部的Unicode 字符.
  • toLocal8Bit() 返回一个用本地编码方式编码的8-bit 字符串.

相反,从这些8位编码字符转换为QString,则需要调用fromLatin1(), fromUtf8(), and fromLocal8Bit().

可以看到, QString 提供了大量的函数和方法使得处理 const char * strings变得简便. 但这也是把双刃剑: 如果字符串都是用US-ASCII or Latin-1编码的,则QString会更方便。但是经常会有一些const char *是8-bit encoding隐式转换而来,这样用QString处理就比较危险了。为了最小化这些风险, 你可以关闭隐式转换:

  • QT_NO_CAST_FROM_ASCII 不允许C风格字符串或指针自动转换为Unicode.
  • QT_RESTRICTED_CAST_FROM_ASCII 允许C风格字符串自动转换为Unicode,但不允许指针自动转换。.
  • QT_NO_CAST_TO_ASCII 不允许QString自动转换为C风格字符串。

具体使用可以在pro文件中添加全局声明:

DEFINES += QT_NO_CAST_FROM_ASCII \

             QT_NO_CAST_TO_ASCII

效率问题

最后来分析下QString的效率问题。首先是QStringLiteral的使用。QStringLiteral不是类名,而是一个宏定义。它的用法是QStringLiteral("hello").它到底有什么用呢?通常,我们用通常用QString("hello")构造QString,在运行时构造函数内需要分配内存,耗费时间。而 QStringLiteral("hello")的用法是在编译阶段就将hello字符串生成QString,成为静态数据。这样在运行阶段就不需要分配内存,在传参数时也不用深度拷贝了。所以,在使用时,对于const char* (不会修改的字符串)可以用QStringLiteral来修饰它以提升效率。

另一个问题是“+”的问题,采用“+”来拼接多个字符串很常见,但是实际上这意味着更多的内存分配,当连接n个字符串,则会有n-1次内存分配,这无疑会增加运行时间。从Qt4.6开始,内部增加了一个QStringBuilder模板类。QStringBuilder使用表达式模板重新解释“%”,当我们用“%”替换“+”时,就会待最终的整个字符串被确定,一次性分配内存空间,然后把字符串一个个拷贝进来。更方便的是,我们不必要把所有的“+”都用“%”替代,Qt提供了全局宏定义以使得所有的“+”都会被以“%”替代处理:

DEFINES += QT_USE_QSTRINGBUILDER

所以,我们可以在pro文件中声明这个宏,这将会大大提高QString的“+”操作效率。

 

发布了76 篇原创文章 · 获赞 63 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/bjtuwayne/article/details/100122128
今日推荐