跳转到内容

C++ 编程/代码/IO/流/字符串

来自维基教科书,自由的教科书

字符串类

[编辑 | 编辑源代码]

字符串类是 C++ 标准库的一部分,用于方便地操作字符序列,以取代处理字符串的静态、不安全的 C 方法。要在程序中使用字符串类,必须包含 <string> 头文件。标准库字符串类可以通过 std 命名空间 访问。

基本模板类是 basic_string<>,其标准特化是 stringwstring

基本用法

[编辑 | 编辑源代码]

声明一个 std 字符串可以通过以下两种方法之一完成

using namespace std;
string std_string;

or
 
std::string std_string;

文本 I/O

[编辑 | 编辑源代码]

本节只处理键盘和文本输入。还有许多其他输入可以读取(鼠标移动和按钮点击等),但这些内容在本节中不会涉及,即使是读取键盘上的特殊键也会被排除在外。

也许字符串类最基本的使用方式是读取用户的文本并将其写入屏幕。在头文件iostream中,C++ 定义了一个名为 cin 的对象,它处理输入的方式与 cout 处理输出的方式非常相似。

// snipped designed to get an integer value from the user
int x; 
std::cin >> x;

>> 运算符将导致执行停止并等待用户输入。如果用户输入有效的整数,它将被转换为整数值并存储在 x 中。

如果用户输入的不是整数,编译器不会报错。相反,它会在x中保留旧内容(一个“随机”的无意义值)并继续执行。

然后可以将其扩展到以下程序

#include <iostream>
#include <string>

int main(){
    std::string name;
    std::cout << "Please enter your first name: ";
    std::cin >> name;
    std::cout << "Welcome " << name << "!" << std::endl;

    return 0;
}


虽然字符串可以包含任何字符的序列,包括空格和空字符,但在使用 cin 和提取运算符(>>)将内容读入字符串时,只会存储第一个空格之前的字符。或者,如果需要整行文本,可以使用 getline 函数

    std::getline(std::cin, name);

获取用户输入

[编辑 | 编辑源代码]

幸运的是,有一种方法可以检查输入语句是否成功。我们可以调用 cin 上的 good 函数来检查所谓的流状态。good 返回一个 bool 值:如果为 true,则上次输入语句成功。如果不是,我们知道之前的某个操作失败了,而且下一个操作也会失败。

因此,从用户获取输入可能看起来像这样

#include <iostream>
using namespace std;
int main () 
{ 
  int x; 
 
  // prompt the user for input 
  cout << "Enter an integer: "; 
 
  // get input 
  cin >> x; 
 
  // check and see if the input statement succeeded 
  if (cin.good() == false) { 
    cout << "That was not an integer." << endl; 
    return -1; 
  } 
 
  // print the value we got from the user 
  cout << x << endl; 
  return 0; 
}

cin 也可以用来输入字符串

string name;

cout << "What is your name? "; 
cin >> name; 
cout << name << endl;

与标准 C 库中的 scanf() 函数一样,此语句只获取输入的第一个单词,并将剩余的单词留给下一个输入语句。因此,如果您运行此程序并输入您的全名,它只会输出您的名字。

您可能还会注意到 >> 运算符没有按预期处理错误(例如,如果您在数字提示中不小心输入了您的姓名)。由于这些问题,读取一行文本并使用该行作为输入可能更合适 - 这是使用名为 getline 的函数来执行的。

string name;

cout << "What is your name? "; 
getline (cin, name); 
cout << name << endl;

getline 的第一个参数是 cin,它表示输入来自哪里。第二个参数是您要存储结果的字符串变量的名称。

getline 会读取整行,直到用户按下回车键或 Enter 键。这对于输入包含空格的字符串很有用。

事实上,getline 通常用于获取任何类型的输入。例如,如果您想让用户输入一个整数,您可以输入一个字符串,然后检查它是否是一个有效的整数。如果是,则可以将其转换为整数值。如果不是,您可以打印一条错误消息并要求用户重试。

要将字符串转换为整数,可以使用在头文件 cstdlib 中定义的 strtol 函数。(请注意,与 strtol 相比,旧函数 atoi 并不安全,而且功能也不如 strtol。)

如果您仍然需要 >> 运算符的功能,则需要创建字符串流,如<sstream>中所述。此流的使用将在后面的章节中讨论。

更高级的字符串操作

[编辑 | 编辑源代码]
Clipboard

要做的事情
详细介绍常用的 std::string 成员函数(部分完成)


我们将使用这个虚拟字符串作为我们一些示例。

string str("Hello World!");

这调用带有 const char* 参数的默认构造函数。默认构造函数创建一个不包含任何内容的字符串,即没有字符,甚至没有 '\0'(但是 std::string 不是以空字符结尾的)。

string str2(str);

将触发复制构造函数。std::string 了解如何对它存储的字符进行深度复制。

string str2 = str;

这将使用赋值运算符复制字符串。此代码的效果与上面的示例中使用复制构造函数相同。

string::size_type string::size() const;
string::size_type string::length() const;

例如,您可以执行以下操作

string::size_type strSize =  str.size();
string::size_type strSize2 = str2.length();

size()length() 方法都返回字符串对象的大小。两者之间没有明显的区别。请记住,字符串中的最后一个字符是 size() - 1,而不是 size()。就像在 C 风格的字符串和数组中一样,std::string 从 0 开始计数。

ostream& operator<<(ostream &out, string &str);
istream& operator>>(istream &in, string &str);

移位运算符(>><<)已被重载,因此您可以对 istreamostream 对象执行 I/O 操作,最值得注意的是 coutcin 和文件流。因此,您可以像这样执行控制台 I/O

std::cout << str << endl;
std::cin >> str;

istream& getline (istream& in, string& str, char delim = '\n');

或者,如果您想一次读取整行,请使用 getline()。请注意,这不是一个成员函数。getline() 将从输入流 in 中检索字符并将其分配给 str,直到遇到 EOFdelimgetline 将在追加数据之前重置输入字符串。delim 可以设置为任何 char 值,并用作通用分隔符。以下是一些示例用法

#include <fstream>
//open a file
std::ifstream file("somefile.cpp");
std::string data, temp;

while( getline(file, temp, '#')) //while data left in file
{
    //append data
    data += temp;
}

std::cout << data;

由于 getline 的工作方式(即它返回输入流),因此您可以嵌套多个 getline() 调用来获取多个字符串;但是,这可能会显著降低可读性。

运算符

[编辑 | 编辑源代码]
char& string::operator[](string::size_type pos);

string 中的 Chars 可以使用重载的下标 ([]) 运算符直接访问,就像在 char 数组中一样。

std::cout << str[0] << str[2];

打印 "Hl"。

std::string 支持从旧的 C 字符串类型 const char* 转换。你也可以将一个简单的 char 分配或追加到一个字符串中。将 char* 分配给 string 就像这样

str = "Hello World!";

如果你想逐个字符地进行,你也可以使用

str = 'H';

毫不奇怪,operator+operator+= 也被定义了!你可以将另一个 string、一个 const char* 或一个 char 追加到任何字符串中。

比较运算符 >, <, ==, >=, <=, != 都对字符串执行比较操作,类似于 C 的 strcmp() 函数。这些返回一个真/假值。

if(str == "Hello World!")
{
 std::cout << "Strings are equal!";
}


搜索字符串

[编辑 | 编辑源代码]
string::size_type string::find(string needle, string::size_type pos = 0) const;

你可以使用 find() 成员函数在另一个字符串中查找字符串的第一个出现位置。find() 将从位置 pos 开始在 this 中查找 needle,并返回 needle 第一次出现的位置。例如

std::string haystack = "Hello World!";
std::string needle = "o";
std::cout << haystack.find(needle);

将简单地打印 "4",这是 str 中 "o" 第一次出现的位置索引。如果我们想要 "World" 中的 "o",我们需要修改 pos 指向第一个出现位置之后。str.find(find, 4) 将返回 4,而 str.find(find, 5) 将返回 7。如果子字符串未找到,find() 将返回 std::string::npos。这个简单的代码在一个字符串中搜索所有 "wiki" 的出现位置,并打印它们的位置

std::string wikistr = "wikipedia is full of wikis (wiki-wiki means fast)";
for(string::size_type i = 0, tfind; (tfind = wikistr.find("wiki", i)) != string::npos; i = tfind + 1)
{
 std::cout << "Found occurrence of 'wiki' at position " << tfind << std::endl;
}

string::size_type string::rfind(string needle, string::size_type pos = string::npos) const;

函数 rfind() 的工作原理类似,只是它返回传递字符串的最后出现位置。

插入/删除

[编辑 | 编辑源代码]
string& string::insert(size_type pos, const string& str);

你可以使用 insert() 成员函数将另一个字符串插入到一个字符串中。例如

string newstr = " Human";
str.insert (5,newstr);

将返回 Hello Human World!

string& string::erase(size_type pos, size_type n);

你可以使用 erase() 从字符串中删除子字符串。例如

str.erase (5,6);

将返回 Hello!

string& string::substr(size_type pos, size_type n);

你可以使用 substr() 从字符串中提取子字符串。例如

string str = "Hello World!";
string part = str.substr(6,5);

将返回 World

向后兼容性

[编辑 | 编辑源代码]
const char* string::c_str() const;
const char* string::data() const;

为了与只接受 char* 参数的 C/C++ 函数向后兼容,你可以使用成员函数 string::c_str()string::data() 返回一个临时的 const char* 字符串,你可以将其传递给函数。这两个函数之间的区别是,c_str() 返回一个以 null 结尾的字符串,而 data() 不一定返回一个以 null 结尾的字符串。因此,如果你的旧函数需要一个以 null 结尾的字符串,请使用 c_str(),否则使用 data()(并且可能还要将字符串的长度作为参数传递)。

字符串连接

[编辑 | 编辑源代码]

字符串可以通过简单地使用 + 运算符连接(追加)在一起。

string firstString = "Hello";
string secondString = " World!";
string finalString = firstString  + secondString;
cout << finalString << endl;

这里的输出将是 "Hello World"

追加字符串

[编辑 | 编辑源代码]

需要注意的是,除了 + 运算符或连接之外,还可以使用 .append(str2) 类成员函数将一个字符串连接到另一个字符串。str2 对象可以是字符串对象或 C 字符串。这将把括号中的字符串添加到调用 append 的字符串中。

还应该注意,append 函数可以用于在字符串中的特定字符位置追加字符串。如果程序员输入 str.append(str2, p, n) ,则从字符串 str2 中位置 p 开始的 n 个字符将被追加到 str 的末尾。例如,在以下代码中,有两个字符串。从第二个字符串中位置 8 开始的 5 个字符将被追加到第一个字符串 str 的末尾。

string str("Watch out for ");
string str2("Llamas, Bears, and Telemarketers!");

str.append(str2, 8, 5);
cout << str << endl;

上面的代码将在第一个字符串的末尾追加单词 Bears,然后在屏幕上打印 Watch out for Bears


字符串转换为有符号整数

[编辑 | 编辑源代码]

有时我们想将字符串转换为数字。为此,我们可以使用 stoi() 函数,它接受一个字符串作为参数并返回该值。

string exString1 = "12023";
string exString2 = "1.23249";
string exString3 = "1232 test";

要将这些字符串转换为数字,我们将字符串变量的 stoi 保存到一个整数变量中。

int exInt1 = stoi(exString1);
int exInt2 = stoi(exString2);
int exInt3 = stoi(exString3);
cout << "Before stoi string:" << exString1 << " and after stoi int:" << exInt1 << endl;
cout << "Before stoi string:" << exString2 << " and after stoi int: " << exInt2 << endl;
cout << "Before stoi string:" << exString3 << " and after stoi int:" << exInt3 << endl;

输出将是:Before stoi string :12023 and after stoi int: 12023 Before stoi string :1 and after stoi int: 1 Before stoi string :1232 and after stoi int: 1232

整数转换为字符串

[编辑 | 编辑源代码]

如果我们想做相反的事情,将一个整数转换为一个字符串,我们可以使用 to_string() 函数,它接受一个整数作为参数,并返回该整数作为字符串。

int exInt = 12023;

要将这个整数转换为字符串,我们调用 to_string() 函数。整数变量作为参数传递给函数。然后该函数将返回该整数作为字符串,然后可以将其分配给一个字符串变量。

string exString = to_string(exInt);
cout << "Before to_string int:" << exInt << " and after to_string string:" << exString << endl;

输出将是:Before to_string int:12023 and after to_string string:12023

字符串格式化

[编辑 | 编辑源代码]

字符串只能追加到其他字符串,但不能追加到数字或其他数据类型,因此类似 std::string("Foo") + 5 这样的代码将不会产生一个内容为 "Foo5" 的字符串。要将其他数据类型转换为字符串,存在类 std::ostringstream,它位于头文件 <sstream> 中。std::ostringstream 的行为与 std::cout 完全相同,唯一的区别是输出不会像操作系统提供的当前标准输出那样,而是输出到一个内部缓冲区中,该缓冲区可以通过 std::ostringstream::str() 方法转换为 std::string

#include <iostream>
#include <sstream>

int main()
{ 
    std::ostringstream buffer;

    // Use the std::ostringstream just like std::cout or other iostreams
    buffer << "You have: " << 5 << " Helloworlds in your inbox";
 
    // Convert the std::ostringstream to a normal string
    std::string text = buffer.str();
 
    std::cout << text << std::endl;
 
    return 0;
}

高级用法

[编辑 | 编辑源代码]
Clipboard

要做的事情
对 basic_string 等的模板参数

华夏公益教科书