字符串
|
字符串的构造函数如下:
构造函数 | 作用 |
---|---|
string(const char*s) | 复制 s 的内容以初始化 string IMPORTANT: s 不得为空指针 |
string(Iter begin, Iter end) | 复制 [begin, end) 中的内容以初始化 |
string(size_t n , char c) | 使用 n 个 c 初始化 |
string(const string& b, size_t start, size_t n) | 使用 b[start, start |
string(const char*s, size_t len) | 如果 len 大于 s 长度,多余的长度是随机内容 |
另外有一个用于表示字符串末尾的常量 std::npos,它的值通常为 uint 的最大值。
另外是一些查找函数,这些函数查找失败时返回 std::npos:
函数签名 | 作用 |
---|---|
find(const string&str, size_t pos) | 从字符串的 pos 开始查找 str 第一次出现时的索引 |
find(const char*, size_t pos) | |
find(const char* s, size_t pos, size_t n) | 从字符串的 pos 开始,查找 s 的前 n 个字符串 |
rfind | 与上面相似,只是是从后面开始查的 |
find_first_of(const char* s) | 查找 s 中 任一 字符在字符串中第一次出现的位置 |
find_last_of | 与上面相似,只是是从后面开始查的 |
find_first_not_of | |
adjacent_find | 在指定范围内查找第一个连续相等的元素 |
如果 find 失败,则返回值为 end() 或者 rend()
=== find_first_of 不是字符串查找函数,而是字符查找函数。但是它也可以接受字符串参数。。。 |
常用的字符串处理函数有:
std::string::find | 字符串查找 |
---|---|
std::string::replace(startPos, OldStr, NewStr) | 字符串替换 |
std::stoi | 字符串转数字 |
std::to_string() | 数字转字符串 |
boost::trim(字符串) | 去除空白字符 |
boost::join(容器, ";") | 容器转字符串 |
boost::replace_all(操作字符串, 被替换字符串, 新字符串) | 字符串替换 |
boost::split(容器, 待分割的字符串, boost::is_any_of(由分界符构成的字符串)) | 字符串分割 |
boost::erase_all(修改串,需要删除的子串) | 字符串删除 |
fmt::format | 字符串格式化 |
std::string::find 查找失败的返回值是 std::string::npos
对于 boost 中的函数而言,使用 _copy 版本的函数代表着产生一个副本,否则则是在原字符串上修改
std 中的 replace 需要配合 find 使用:
s.find("world"); s = s.replace(startPos, OldStr, NewStr)
对于字符串格式化而言,更加推荐使用 fmt
此外,还有一些辅助函数:
boost::to_upper() | 转为大写 |
boost::to_lower() | 转为小写 |
boost::starts_with() | 判断开头 |
boost::ends_with() | 判断结尾 |
boost::contains() | 判断包含 |
以及一些谓词:
boost::is_space() | 空格 |
boost::is_digit() | 数字 |
参见字符串处理方式
本来是不想写的,因为一般情况下我直接就用 boost 了,但是昨天做题的时候系统输入的内容不是标准的,得自己解析,而且还只能用标准库。当时考试时比较紧张,一直没写出来,后来换 Python 了,今天做个笔记吧。
第一种是截取指定字符串,通常是配合 substr 和 find_first_of 使用的:
// data = "1,2,3,4,5"
while(data.length()) {
auto tracatePos = data.find_first_of(',');
if(tracatePos == string::npos) tracatePos = data.length();
auto tmp = data.substr(0, tracatePos);
arr1.push_back(stoi(tmp));
data.erase(0, tracatePos + 1);
}
string 的 substr 和 erase 实在指定 pos 之前截取的,所以后面使用 erase 的时候需要将 pos + 1
另外一种比较坑的情况是 erase 接受 int 参数,但是行为比较奇怪,往往没法得到正确的结果,正确的方式是使用迭代器
stringstream
使用 istringstream 可以方便地将字符串中的数据储存到变量中:
std::string input = "41 3.14 false hello world";
std::istringstream stream(input);
int n;
double f;
bool b;
stream >> n >> f >> std::boolalpha >> b;
// 用 streambuf 重载释出剩余内容
stream >> std::cout.rdbuf();
std::cout << '\n';
正则表达式
目前而言,C++ 可选的正则表达式引擎有:
引擎 | 解释 |
---|---|
主要为 Intel 优化的引擎。不支持 ARM。完整版需要采购。 | |
由 Google 开发的正则表达式引擎。 | |
perl 兼容的引擎。支持 jit 模式 | |
编译期正则表达式 | |
Boost::regex | 性能不太好 |
std::regex | 性能不咋滴。 |
正则表达式的性能测试可以在 regex-performance 查看。
re2
普通匹配:
assert(RE2::FullMatch("hello", "h.*o"))
assert(!RE2::FullMatch("hello", "e"))
assert(RE2::PartialMatch("hello", "h.*o"))
assert(RE2::PartialMatch("hello", "e"))
子表达式:
// Successful parsing.
int i;
string s;
assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s, &i));
assert(s == "ruby");
assert(i == 1234);
// Fails: "ruby" cannot be parsed as an integer.
assert(!RE2::FullMatch("ruby", "(.+)", &i));
// Success; does not extract the number.
assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s));
// Success; skips NULL argument.
assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", (void*)NULL, &i));
// Fails: integer overflow keeps value from being stored in i.
assert(!RE2::FullMatch("ruby:123456789123", "(\\w+):(\\d+)", &s, &i));
预编译正则表达式:
RE2 re("(\\w+):(\\d+)");
assert(re.ok()); // compiled; if not, see re.error();
assert(RE2::FullMatch("ruby:1234", re, &s, &i));
assert(RE2::FullMatch("ruby:1234", re, &s));
assert(RE2::FullMatch("ruby:1234", re, (void*)NULL, &i));
assert(!RE2::FullMatch("ruby:123456789123", re, &s, &i));
禁止打印错误消息:
RE2 re("(ab", RE2::Quiet); // don't write to stderr for parser failure
assert(!re.ok()); // can check re.error() for details