Qt&C++技术分析2 - 标准库与 QT 字符串处理

标准库与 QT 字符串处理


标准库类模板

C++使用类模板 basic_string 来存放字符串数据,并提供了一组成员函数来处理该字符串

basic_string 还具有一个明显的优势:自动内存管理功能


模板参数与构造函数

类 string 及 wstring 是 basic_string 特化的结果

typedef  basic_string<char>  string;
typedef  basic_string<wchar_t>  wstring;

basic_string 常见的构造函数及其使用方法

对于 wchar_t 类型的 basic_string,最好在字符串常量的前面加上前缀“L”

#include <string>
#include <iostream>
using namespace std;
int main()
{
    basic_string<char> s1;
    basic_string<char> s2 ("hello world");
    basic_string<char> s3 ("hello world", 5);
    basic_string<char> s4 ( s2, 6, 5);
    cout << s1 << endl << s2 << endl << s3 << endl << s4 << endl;

    // 加了L前缀的字符串
    basic_string<wchar_t> ws (L"得友难失友易(A friend is easier lost than
    found)");
    wcout.imbue(locale("chs"));
    wcout << "size is: " << sizeof(ws[7]) << endl << ws << endl;
}

basic_string 的其他成员函数

c_str() 该函数返回一个指针,指向 basic_string 中存放的字符串数据
对于 string 类型,该函数返回char *;
对于 wstring 类型,该函数返回wchar_t *;

basic_string 的类模板存在一个专门存放字符串长度的成员变量,通过 length()直接获取字符串长度,可以相对于 strlen()方法获取长度节省很多时间


QString

QString 能对 Unicode 字符串进行拼接、查找等操作

不建议使用 basic_string 中的 wstring 替换掉 QString,因为前者对于标点符号判断等其他操作支持较差,而后者封装完善便于拿来即用


QString 特性

利用 fromLocal8Bit(),将该字符串转换为 Unicode 编码的字符

QString 的成员函数 data() 返回一个指针,指向 QChar 序列

QString 自带的字符编码转换功能展示:

// 定义 main 函数
int main()
{
    // 定义一个 char* 类型的字符串 humor,包含了英文和中文字符
    char * humor = "Your future depends on your dream. So go to sleep.\n"
                    "你的梦想决定你的未来,所以睡觉去吧。";

    // 将 humor 转换为 QString 类型的字符串 qs,使用 fromLocal8Bit 方法将 humor 中的字符转换为本地编码
    QString qs = QString::fromLocal8Bit(humor);

    // 将 qs 转换为 QByteArray 类型的数据 data,使用 toUtf8 方法将 qs 中的字符转换为 UTF-8 编码
    QByteArray data = qs.toUtf8();

    // 打开文件 utf8.txt,以二进制模式写入数据
    ofstream of("utf8.txt", ios::binary);

    // 将 data 中的数据写入文件,使用 data.data() 获取数据指针,data.length() 获取数据长度
    of.write(data.data(), data.length());
}

QByteArray

QByteArray 被用来存放长度可变的字节序列,其中的字节序列被存放在一个地址连续的内存块中

该类总会在字节序列的末尾添加一个额外的“\0”字符


国际化与区域文化


区域文化

C++标准库提供了类 locale 以及 facet ,分别用来描述某个区域的区域文化以及文化刻面

所有流对象都会共享一个全局的 locale 对象

一般的,开发者不需要知道 facet 的原理,直接使用 locale 即可实现区域文焕转换设定
下方代码展示了使用 cout 输出区域文化为德国的文本

#include <iostream>
#include <locale>
using namespace std;
int main( )
{
    double x = 1234567.123456;
    cout.imbue( locale( "German_germany" ) );①
    cout << fixed << x << endl;
}

facet

每个 facet 子类描述某个文化刻面。C++标准库定义了 12 个常用的 facet 子类,来刻画时间、货币等表达方式

facet 对象不能够单独存在,它们必须隶属于某个 locale 对象
通过调用函数模板 use_facet<>可以获得一个 locale 对象中某个 facet 对象的引用


numpunct

numpunct 是 facet 的一个子类,可以通过 use_facet 获取 facet 对象后对其实例化得到 numpunct 对象

#include <locale>
#include <iostream>

// 定义 main 函数
int main()
{
    // 创建一个 locale 对象 os_locale,使用默认本地化设置
    locale os_locale("");

    // 获取 os_locale 的数字标点符号,使用 use_facet 方法获取 numpunct<char> 类型的 facet 对象
    const numpunct<char>& np = use_facet<numpunct<char>>(os_locale);

    // 输出数字标点符号的信息,包括小数点、千位分隔符、true/false 字符串等
    std::cout << "number punctuation of " << os_locale.name() << std::endl;
    std::cout << np.decimal_point() << " "
              << np.thousands_sep() << " "
              << np.falsename() << " " << np.truename() << std::endl;

    // 获取数字分组信息,输出每个分组的长度
    std::string group = np.grouping();
    for (int i = 0; i < group.length(); i++) {
        std::cout << i << "th grouping is: " << (int)group[i] << std::endl;
    }
}

time_get

类模板 time_get 对一个表示日期和时间的字符序列进行解析,将其中的信息存放在结构体 tm 中

类模板 time_get 的基本使用方法

#include <iostream>
#include <sstream>
#include <locale>

// 定义 main 函数
int main()
{
    // 创建一个 locale 对象 loc,使用默认本地化设置
    locale loc;

    // 获取 loc 的 time_get facet 对象 tg,用于解析时间信息
    const time_get<char>& tg = use_facet<time_get<char>>(loc);

    // 获取日期的顺序信息,使用 date_order() 方法获取日期的顺序,返回值为整数
    int idx = tg.date_order();

    // 输出本地化设置的名称和日期的顺序信息,message 数组用于将整数转换为字符串
    char *message[] = {"no_order", "dmy", "mdy", "ymd", "ydm"};
    std::cout << loc.name() << std::endl << "date order " << message[idx] << std::endl;

    // 解析时间信息,使用 istringstream 类创建一个输入流 iss,包含了要解析的时间字符串 "10:26:00"
    std::ios::iostate state = 0;
    std::istringstream iss("10:26:00");

    // 创建一个 istreambuf_iterator 对象 itbegin,指向 iss 的开头
    std::istreambuf_iterator<char> itbegin(iss);

    // 创建一个 istreambuf_iterator 对象 itend,指向 iss 的结尾
    std::istreambuf_iterator<char> itend;

    // 创建一个 tm 结构体对象 time,用于存储解析后的时间信息
    std::tm time;

    // 使用 time_get 的 get_time 方法解析时间信息,将结果存储在 time 中
    tg.get_time(itbegin, itend, iss, state, &time);

    // 输出解析后的时间信息
    std::cout << time.tm_hour << ":" << time.tm_min << ":" << time.tm_sec << std::endl;
}

time_put

类模板 time_put 将存放在结构体 tm 中的日期和时间信息以某种特定的格式转化为一个字符序列

使用场景较少,不浪费过多笔墨介绍该类模板


codecvt

类模板 codecvt 将某一种编码的字符串转换为另外一种编码的字符串

此为对应模板以及三个模板参数的含义

  • internT 表示一个字符串在计算机内部的编码类型
  • externT 表示该字符串在外部存储设备(比如文件系统)中的编码类型
  • stateT 是一个表示转换状态的类型

template <class internT,class externT,class stateT> codecvt


类模板 codecvt 的成员函数 in 的功能

#include <iostream>
#include <locale>

// 定义 main 函数
int main()
{
    // 定义 codecvt 类型的别名 cvt_type
    typedef codecvt<wchar_t, char, mbstate_t> cvt_type;

    // 创建一个 locale 对象 loc,使用默认本地化设置
    locale loc;

    // 获取 loc 的 codecvt facet 对象 cvt,用于字符编码转换
    const cvt_type& cvt = use_facet<cvt_type>(loc);

    // 定义字符数组,src 为待转换的字符串,dst 为存储转换结果的字符串
    const int size = 20;
    const char* p1, src[size] = "hello world!";
    wchar_t* p2, dst[size];

    // 定义 mbstate_t 对象 state,用于存储转换过程中的状态信息
    mbstate_t state;

    // 使用 cvt.in() 方法将 src 中的字符转换为 dst 中的宽字符
    cvt_type::result result = cvt.in(state,
                                     src, src + size, p1,
                                     dst, dst + size, p2);

    // 如果转换成功,输出转换结果
    if (result == cvt_type::ok) {
        std::wcout << dst << std::endl;
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Zhillery

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

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

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

打赏作者

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

抵扣说明:

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

余额充值