65.9K
CodeProject 正在变化。 阅读更多。
Home

STL std::string 的实用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.21/5 (24投票s)

2007年3月26日

CPOL

3分钟阅读

viewsIcon

552792

downloadIcon

972

std::string 的实用函数。

STL std::string 的实用程序

很多程序员都熟悉各种字符串对象的操作,例如 lengthsubstringfindcharAttoLowerCasetoUpperCasetrimequalsIgnoreCasestartsWithendsWithparseInttoStringsplit 等等。

现在,如果您正在使用 STL 及其 string 类 std::string,您将如何实现上述这些操作呢?

当然,std::string 提供了一些方法来实现上述部分操作。它们是:

  • length():获取字符串的长度。
  • substr():获取字符串的子字符串。
  • at()/operator []:获取字符串中指定位置的字符。
  • find/rfind():在字符串中向前/向后查找子字符串。
  • find_first_of():查找第一个匹配指定字符集的字符。
  • find_first_not_of():查找第一个不匹配指定字符集的字符。
  • find_last_of():查找最后一个匹配指定字符集的字符。
  • find_last_not_of():查找最后一个不匹配指定字符集的字符。

有关更多 std::string 方法,请参阅文档。

有些操作没有直接实现为 std::string 方法,但我们可以从 algorithm.h 中找到实现方法。当然,这些实现也使用了 std::string 的现有方法。

将字符串转换为大写/小写

std::transform(str.begin(), str.end(), str.begin(), tolower);
std::transform(str.begin(), str.end(), str.begin(), toupper);

有关 std::transform 函数的详细信息,请参阅文档。

修剪字符串两侧的空格

修剪左侧空格

string::iterator i;
for (i = str.begin(); i != str.end(); i++) {
    if (!isspace(*i)) {
        break;
    }
}
if (i == str.end()) {
    str.clear();
} else {
    str.erase(str.begin(), i);
}

修剪右侧空格

string::iterator i;
for (i = str.end() - 1; ;i--) {
    if (!isspace(*i)) {
        str.erase(i + 1, str.end());
        break;
    }
    if (i == str.begin()) {
        str.clear();
        break;
    }
}

修剪两侧空格

先修剪左侧空格,再修剪右侧空格。从而实现两侧空格的修剪。

通过重复字符或子字符串创建字符串

如果您想通过重复子字符串来创建字符串,您必须使用循环来实现。

string repeat(const string& str, int n) {
    string s;
    for (int i = 0; i < n; i++) {
        s += str;
    }
    return s;
}

但是,如果您只需要重复一个字符,std::string 有一个构造函数可以实现。

string repeat(char c, int n) {
    return string(n, c);
}

忽略大小写比较

这很有趣。我们应该复制要比较的两个字符串。然后将它们全部转换为小写。最后,只需比较两个小写字符串。

Starts with 和 EndsWith

StartsWith

str.find(substr) == 0;

如果结果为 true,则表示 strsubstr 开头。

EndsWith

size_t i = str.rfind(substr);
return (i != string::npos) && (i == (str.length() - substr.length()));

如果结果为 true,则表示 strsubstr 结尾。

还有另一种方法可以做到。只需获取左侧或右侧的子字符串进行比较。因为我不想计算字符串长度是否足够,所以我使用了 findrfind 来实现。

从字符串解析数字/布尔值

对于这些操作,atoiatol 以及其他一些 C 函数都可以。但我希望使用 C++ 的方式来实现。所以我选择了 std::istringstream。该类在 sstream.h 中。

一个模板函数可以处理大部分情况,但不包括布尔值。

template<class T> parseString(const std::string& str) {
    T value;
    std::istringstream iss(str);
    iss >> value;
    return value;
}

模板函数可以将 0 解析为 false,将其他数字解析为 true。但它不能将 "false" 解析为 false,也不能将 "true" 解析为 true。所以我编写了一个特殊函数。

template<bool>
bool parseString(const std::string& str) {
    bool value;
    std::istringstream iss(str);
    iss >> boolalpha >> value;
    return value;
}

正如您所见,我将 std::boolalpha 标志传递给输入流,然后输入流就可以识别字面量 bool 值。

使用类似的方法解析十六进制字符串是可能的。这次我应该将 std::hex 标志传递给流。

template<class T> parseHexString(const std::string& str) {
    T value;
    std::istringstream iss(str);
    iss >> hex >> value;
    return value;
}

转换为字符串的例程

就像从字符串解析一样,我将使用 std::ostringstream 来从其他类型的值获取字符串。该类也在 sstream.h 中。这里展示了相关的三个函数。

template<class T> std::string toString(const T& value) {
    std::ostringstream oss;
    oss << value;
    return oss.str();
}
string toString(const bool& value) {
    ostringstream oss;
    oss << boolalpha << value;
    return oss.str();
}
template<class T> std::string toHexString(const T& value, int width) {
    std::ostringstream oss;
    oss << hex;
    if (width > 0) {
        oss << setw(width) 
            << setfill('0');
    }
    oss << value;
    return oss.str();
}

您注意到 setwsetfill 了吗?它们仍然是需要参数的标志。std::setw 允许流中的输出内容占据固定宽度。如果长度不够,默认情况下会用空格填充。std::setfill 用于更改填充字符。如果您想控制对齐,可以使用 std::leftstd::right 标志。

哦,我忘了告诉您,setwsetfill 需要 iomanip.h 头文件。

分割和分词

我认为分割函数应该通过分词器来实现。所以我先编写了一个分词器。我们可以使用 find_first_offind_first_not_of 方法来获取每个标记。下面是 Tokenizer 类的 nextToken 方法。

bool Tokenizer::nextToken(const std::string& delimiters) {
    // find the start character of the next token.
    size_t i = m_String.find_first_not_of(delimiters, m_Offset);
    if (i == string::npos) {
        m_Offset = m_String.length();
        return false;
    }

    // find the end of the token.
    size_t j = m_String.find_first_of(delimiters, i);
    if (j == string::npos) {
        m_Token = m_String.substr(i);
        m_Offset = m_String.length();
        return true;
    }

    // to intercept the token and save current position
    m_Token = m_String.substr(i, j - i);
    m_Offset = j;
    return true;
}

完整的标记器可在源代码存档中找到。您可以从上面的链接下载。所有其他函数仍在源代码文件中。

© . All rights reserved.