Qt中的字符串操作
3.1 概述
对于一个应用程序来说,文本操作几乎是无处不在的,无论是窗体应用还是控制台应用都难免要做诸如显示,输入,处理文本之类的操作。因此字符串作为文本的载体也就必不可少,大多数编程语言都直接或者间接的提供了字符串类型以方便我们操作字符串,比如C++标准库提供的字符串类std::string。Qt作为一个跨平台开发框架实现了自己的字符串类型QString,该类型广泛应用于Qt应用程序中,也是各种Qt图形用户控件的基础。鉴于上面这些考虑以及自己学习中遇到的麻烦,决定先从QString来入手各种组件的学习。
3.2 通过QDebug输出调试信息
在正式接触QString之前我们先来看一下在Qt中如何向控制台输出信息,假设要向控制台输出Hello,World!,在C++学习中我们最常用的做法就是:
//直接输出string literals
std::cout<<"Hello,World!"<<std::endl;
//输出String类的对象
std::string str("Hello,String!");
std::cout<<str<<std::endl;
在Qt应用程序开发中当然也可以这样做,能否成功使用std::cout来输出这些字符串依赖于输出操作符能否正确的识别作为右操作数的字符串,在C++中这些操作已经通过**重载输出操作符<<**来完成了。而在Qt中因为其内部控件大量使用QString类型,这种类型不能被输出操作符识别,因此这样的方法也就不可行:
QString str("Hello,QString!");
std::cout<<str<<std<<endl; //会报错,输出操作符不认识QString类型
为了完成这些Qt内置数据类型的正确输出,在Qt中我们通常使用qDebug()(严格来说这不是函数,而是一个定义在头文件QtGlobal中的宏),他有下面两种常见的用法,第一种方法中qDebug()就类似与C语言的库函数printf(),对于控制台应用程序该函数会把参数输出到控制台:
qDebug("Items in list: %d", myList.size());
另一种用法更加简洁,如同C++操作输出流的方法,这种方法需要包含头文件QDebug才能正常使用(因为该方法中会用到QDebug对象):
#include <QDebug>
#include <QString>
QString qStr("Hello,QString!");
qDebug()<<qStr;//使用qDebug输出结尾默认已经换行,用不着endl
注意两点:
- 上面提到qDebug宏在头文件QtGlobal中定义,不过由于该头文件在大多数其他头文件中已经被包含,所以不用手动再次包含。比如在Qt主程序中默认包含的QCoreApplication文件中就有QtGlobal。
- 在引入QDebug头文件后,qDebug宏会返回一个QDebug类的实例。
- 如果定义了宏QT_NO_DEBUG_OUTPUT,则qDebug会失效。
3.3 QString对象的构造和访问
知道了如何对QString进行输出之后,就可以进一步来看QString类的用法了,首先先了解一下QString是什么,阅读官方文档之后大概可以摘出来下面几点:
- QString是由QChars构成的序列,而QChars支持UNICODE编码
- QString支持std::string和std::wstring的相互转换
- QString底层实现采用 implicit sharing (copy-on-write) 技术来减少内存开支和不必要的数据拷贝。
- 跨各种平台,由Qt保证。
然后我们注意考察QString的常见用法,首先是创建字符串,最简单地,我们可以*通过一个C风格字符串(const char )来初始化一个QString:
QString str = "Hello,World!";
也可以通过QChars数组的方式来构造一个字符串,此时必须指定字符数组大小,否则会一直找到’\0’才停止:
const QChar data[5] = {'H','e','l','l','o'};
QString str(data,5);
const QChar data1[6] = {'H','e','l','l','o','\0'};
QString str(data1);
还有一种方法是通过resize()调整QString的大小,然后为每一个元素逐一赋值,而字符串的访问有两种方法,对于普通字符串可以直接使用运算符[],得到一个可以用作赋值运算左值的字符引用:
QString str;
str.resize(4);
str[0] = QChar('U');
str[1] = QChar('n');
str[2] = QChar(0x10e3);
str[3] = QChar(0x03a3);
对于常量字符串,或者其他要求只读的场合,可以用QString的at方法来取得索引位置的字符:
const QString str("gabcdefg");
//遍历字符串,找到其中介于a-f之间的字符并输出提示信息
for (int i = 0; i < str.size(); ++i) {
if (str.at(i) >= QChar('a') && str.at(i) <= QChar('f'))
qDebug() << "Found character in range [a-f]";
}
用于索引QString中的字符的函数除了at以外还有mid,ledf,right等:
const QChar at(int position) const
QString mid(int position, int n = -1) const
QString left(int n) const
QString right(int n) const
现在小结并列举一下QString类的全部构造函数:
QString(const QByteArray &ba) //通过字节数组构造,会转换为UNICODE
QString(const char *str) //通过C风格字符串构造
QString(QString &&other) //移动构造函数
QString(const QString &other) //复制构造函数
QString(QLatin1String str) //通过Latin-1编码(单字节编码,兼容ASCII)的字符串构造
QString(int size, QChar ch) //通过size个QChar构造
QString(QChar ch) //通过一个QChar构造长度为1的QString
QString(const QChar *unicode, int size = -1) //通过QChar数组构造,如果不指定size则检查到'\0'停止
QString() //空字符串
3.4 QString的比较
QString可以和字符串字面值之间进行比较:
QString qStr5 = "string";
if(qStr5 == "string"){
qDebug()<<"true";
}
if(qStr5 != "String"){
qDebug()<<"false";
}
QString重载的比较运算发非常多,具体信息可以在Qt官方文档查看。
3.5 类型转换
3.5.1 不同类型字符串之间的转换
Qt还提供了QString和C风格字符串之间的转换方法,*如果要将C风格字符串转换为QString类型直接使用QString(const char )构造函数即可,上面的例子已经展示过了。QString对象向C风格字符串转换则可以使用qPrintable宏来完成:
qDebug()<<qPrintable(qStr5);
//下面的做法是错误的
const char *cStr = qPrintable(qStr5);
qDebug()<<cStr;
**需要注意的是,qPrintable宏返回的const char 在这条语句之后便无效了,再使用该指针会引发指针错误,因此qPrintable通常只用于实参要求const char 的场合。
3.5.2 QString转数值类型
此处直接使用QString对象的toInt(), toLongLong(), toDouble()等方法即可:
QString str = "12";
int i = str.toInt();//i = 12
QString str1 = "1234.56";
str1.toFloat();
bool ok;
QString str2 = "R2D2";
str2.toFloat(&ok);
QString str3 = "1234.56 Volt";
str3.toFloat(&ok);
这些函数使用方法大抵类似,就不用一一举例了。
注意这些函数可以接收一个布尔指针,如果该指针不是nullptr,则转换成功时把指针置true,失败时置为false。
3.5.3 数值类型转QString
通过调用QString对象的成员函数setNum():
QString str;
str.setNum(1234);
3.6 处理字符串
3.6.1 追加字符串
QString str = "and";
//追加到开头
str.prepend("rock "); // str == "rock and"
//追加到结尾
str.append(" roll"); // str == "rock and roll"
//指定位置处插入字符串
str.insert(5,"Hello");
下面列出insert的全部重载版本:
QString & insert(int position, const QString &str)
QString & insert(int position, QChar ch)
QString & insert(int position, const QChar *unicode, int size)
QString & insert(int position, const QStringRef &str)
QString & insert(int position, QLatin1String str)
QString & insert(int position, const char *str)
QString & insert(int position, const QByteArray &str)
3.6.2 替换字符串
QString str = "rock and roll";
str.replace(5, 3, "&"); // str == "rock & roll"
replace的全部重载版本:
QString & replace(int position, int n, const QString &after)
QString & replace(int position, int n, QChar after)
QString & replace(int position, int n, const QChar *unicode, int size)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(const QChar *before, int blen, const QChar *after, int alen, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(QLatin1String before, QLatin1String after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(QLatin1String before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(const QString &before, QLatin1String after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(QChar ch, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(QChar c, QLatin1String after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & replace(const QRegExp &rx, const QString &after)
QString & replace(const QRegularExpression &re, const QString &after)
3.6.3 删除子串
利用remove从字符串中删除某一子串,下面是最简单的例子,通过其实位置和长度两个参数来指定子串:
QString s = "Montreal";
s.remove(1, 4);
// s == "Meal"
各种重载版本如下:
QString & remove(int position, int n)
QString & remove(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & remove(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & remove(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive)
QString & remove(const QRegExp &rx)
QString & remove(const QRegularExpression &re)
3.6.4 查找子串
indexOf会返回子串在字符串中首次出现的位置:
QString x = "Hello,WoHelrld!";
QString y = "Hel";
x.indexOf(y);
x.indexOf(y, 1); //第二个参数是指定起始位置,默认为0
该函数有很多重载版本,如下:
int indexOf(QLatin1String str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
int indexOf(QChar ch, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
int indexOf(const QString &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
int indexOf(const QStringRef &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
int indexOf(QStringView str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
int indexOf(const QRegExp &rx, int from = 0) const
int indexOf(QRegExp &rx, int from = 0) const
int indexOf(const QRegularExpression &re, int from = 0) const
int indexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const
count会得到某个子字符串的出现次数:
QString s = "Hello World";
qDebug() << s.count("l");
查找该字符串是否以某个子字符串开始或者结束:
QString s = "hello,qstring!";
bool b1 = s.startsWith("hel");
bool b2 = s.endsWith("ing");
3.7 其他常用方法
3.7.1 分割字符串:
QString str = "a,,b,c";
QStringList list1 = str.split(','); // list1: [ "a", "", "b", "c" ]
3.7.2 大小写转换:
返回的是一个全大写,或者全为小写的字符串拷贝。
QStrig str = "abcdefg";
str.toUpper();
str.toLower();
3.7.3 获取字符串长度
获取字符串长度有两个方法,他们是一样的:
QString str = "Returns the number of characters in this string. Equivalent to size().";
str.length();
str.size();