字符串(String)与流(Stream)
一、C++中字符串(String)
字符串(String):就是(可能是空的)字符序列。
C++中的字符串在概念上和Java中的字符串类似。
C++字符串用string类型来表示。在使用string类型之前,必须在程序中包含如下头文件
#include可以通过调用如下方法:
str.length()来获取字符串中字符的长度。
可以通过如下方式来从一个字符串中读取一个字符
str[index]尽管字符串不是数组,但是上述语法是一个方便的语法方式。
字符操作
在C++中,头文件<cctype>包含各种有用的处理字符的函数,以下函数用来检查给定的类型是否是一个给定的字符
isalpha, isdigit, isalnum, islower, isupper, isspace, ispunct.
跟Java中字符串不同,C++中字符串是可变的,可以被修改。
改变单个字符的方式:
str[index] = ch
附加更多的文本方式:
str += text这些操作直接改变字符串本身,而不是对字符串的副本进行操作。
在C++中,==操作符可以直接拿来用于字符串的比较
if(str1 == str2){ /* string match */}在一个字符串中查询其他一些字符,可以使用find,如果找不到,则返回string::npos,而不是-1。
if(str1.find(str2) != string::npos){ /* found str2 inside str1 */}通过调用substr方法从string中获取substring。
substr方法需要知道substring的开始位置和长度(不是结束位置)
string allButFirstChar = str.substr(1);string lastFiveChars = str.substr(str.length() - 5, 5);
与Java语言不同的时,在C++中,只能连接字符串和字符到其他的字符串中。
在本课程中,提供了"strlib.h"库,让字符串操作更加容易
string s = "I like " + integerToString(137);strlib.h的代码如下:
/* * File: strlib.h * -------------- * This file exports several useful string functions that are not * included in the C++ string library. */#ifndef _strlib_h#define _strlib_h#includestrlib.c的代码如下:#include /* * Function: integerToString * Usage: string s = integerToString(n); * ------------------------------------- * Converts an integer into the corresponding string of digits. * For example, calling integerToString(123)
returns * the string"123"
. */std::string integerToString(int n);/* * Function: stringToInteger * Usage: int n = stringToInteger(str); * ------------------------------------ * Converts a string of digits into an integer. If the string is not a * legal integer or contains extraneous characters other than whitespace, *stringToInteger
callserror
with an * appropriate message. */int stringToInteger(std::string str);/* * Function: realToString * Usage: string s = realToString(d); * ---------------------------------- * Converts a floating-point number into the corresponding string form. * For example, callingrealToString(23.45)
returns * the string"23.45"
. */std::string realToString(double d);/* * Function: stringToReal * Usage: double d = stringToReal(str); * ------------------------------------ * Converts a string representing a real number into its corresponding * value. If the string is not a legal floating-point number or contains * extraneous characters other than whitespace,stringToReal
* callserror
with an appropriate message. */double stringToReal(std::string str);/* * Function: toUpperCase * Usage: string s = toUpperCase(str); * ----------------------------------- * Returns a new string in which all lowercase characters have been converted * into their uppercase equivalents. */std::string toUpperCase(std::string str);/* * Function: toLowerCase * Usage: string s = toLowerCase(str); * ----------------------------------- * Returns a new string in which all uppercase characters have been converted * into their lowercase equivalents. */std::string toLowerCase(std::string str);/* * Function: equalsIgnoreCase * Usage: if (equalsIgnoreCase(s1, s2)) ... * ---------------------------------------- * Returnstrue
ifs1
ands2
are * equal discounting differences in case. */bool equalsIgnoreCase(std::string s1, std::string s2);/* * Function: startsWith * Usage: if (startsWith(str, prefix)) ... * --------------------------------------- * Returnstrue
if the stringstr
starts with * the specified prefix, which may be either a string or a character. */bool startsWith(std::string str, std::string prefix);bool startsWith(std::string str, char prefix);/* * Function: endsWith * Usage: if (endsWith(str, suffix)) ... * ------------------------------------- * Returnstrue
if the stringstr
ends with * the specified suffix, which may be either a string or a character. */bool endsWith(std::string str, std::string suffix);bool endsWith(std::string str, char suffix);/* * Function: trim * Usage: string trimmed = trim(str); * ---------------------------------- * Returns a new string after removing any whitespace characters * from the beginning and end of the argument. */std::string trim(std::string str);/* Private section *//**********************************************************************//* Note: Everything below this point in the file is logically part *//* of the implementation and should not be of interest to clients. *//**********************************************************************//* * Friend function: writeQuotedString * Usage: writeQuotedString(outfile, str, forceQuotes); * ---------------------------------------------------- * Writes the string str to outfile surrounded by double quotes, converting * special characters to escape sequences, as necessary. If the optional * parameter forceQuotes is explicitly set to false, quotes are included * in the output only if necessary. */void writeQuotedString(std::ostream & os, const std::string & str, bool forceQuotes = true);/* * Friend function: readQuotedString * Usage: readQuotedString(infile, str); * ------------------------------------- * Reads the next string from infile into the reference parameter str. * If the first character (other than whitespace) is either a single * or a double quote, this function reads characters up to the * matching quote, processing standard escape sequences as it goes. * If not, readString reads characters up to any of the characters * in the string STRING_DELIMITERS in the implementation file. */void readQuotedString(std::istream & is, std::string & str);/* * Friend function: stringNeedsQuoting * Usage: if (stringNeedsQuoting(str)) ... * --------------------------------------- * Checks whether the string needs quoting in order to be read correctly. */bool stringNeedsQuoting(const std::string & str);/* * Friend function: writeGenericValue * Usage: writeGenericValue(os, value, forceQuotes); * ------------------------------------------------- * Writes a generic value to the output stream. If that value is a string, * this function uses writeQuotedString to write the value. */templatevoid writeGenericValue(std::ostream & os, const ValueType & value, bool forceQuotes) { os << value;}template <>inline void writeGenericValue(std::ostream & os, const std::string & value, bool forceQuotes) { writeQuotedString(os, value, forceQuotes);}/* * Friend function: readGenericValue * Usage: readGenericValue(is, value); * ----------------------------------- * Reads a generic value from the input stream. If that value is a string, * this function uses readQuotedString to read the value. */template void readGenericValue(std::istream & is, ValueType & value) { is >> value;}template <>inline void readGenericValue(std::istream & is, std::string & value) { readQuotedString(is, value);}#endif
/* * File: strlib.cpp * ---------------- * This file implements the strlib.h interface. */#include在C++中,有两种类型的字符串:#include #include #include "error.h"#include "strlib.h"using namespace std;/* Function prototypes *//* * Implementation notes: numeric conversion * ---------------------------------------- * These functions use the library to perform the conversion. */string integerToString(int n) { ostringstream stream; stream << n; return stream.str();}int stringToInteger(string str) { istringstream stream(str); int value; stream >> value >> ws; if (stream.fail() || !stream.eof()) { error("stringToInteger: Illegal integer format (" + str + ")"); } return value;}string realToString(double d) { ostringstream stream; stream << uppercase << d; return stream.str();}double stringToReal(string str) { istringstream stream(str); double value; stream >> value >> ws; if (stream.fail() || !stream.eof()) { error("stringToReal: Illegal floating-point format (" + str + ")"); } return value;}/* * Implementation notes: case conversion * ------------------------------------- * The functions toUpperCase and toLowerCase return a new string whose * characters appear in the desired case. These implementations rely on * the fact that the characters in the string are copied when the * argument is passed to the function, which makes it possible to change * the case of the copy without affecting the original. */string toUpperCase(string str) { int nChars = str.length(); for (int i = 0; i < nChars; i++) { str[i] = toupper(str[i]); } return str;}string toLowerCase(string str) { int nChars = str.length(); for (int i = 0; i < nChars; i++) { str[i] = tolower(str[i]); } return str;}/* * Implementation notes: equalsIgnoreCase * -------------------------------------- * This implementation uses a for loop to cycle through the characters in * each string. Converting each string to uppercase and then comparing * the results makes for a shorter but less efficient implementation. */bool equalsIgnoreCase(string s1, string s2) { if (s1.length() != s2.length()) return false; int nChars = s1.length(); for (int i = 0; i < nChars; i++) { if (tolower(s1[i]) != tolower(s2[i])) return false; } return true;}/* * Implementation notes: startsWith, endsWith * ------------------------------------------ * These implementations are overloaded to allow the second argument to * be either a string or a character. */bool startsWith(string str, string prefix) { if (str.length() < prefix.length()) return false; int nChars = prefix.length(); for (int i = 0; i < nChars; i++) { if (str[i] != prefix[i]) return false; } return true;}bool startsWith(string str, char prefix) { return str.length() > 0 && str[0] == prefix;}bool endsWith(string str, string suffix) { int nChars = suffix.length(); int start = str.length() - nChars; if (start < 0) return false; for (int i = 0; i < nChars; i++) { if (str[start + i] != suffix[i]) return false; } return true;}bool endsWith(string str, char suffix) { return str.length() > 0 && str[str.length() - 1] == suffix;}string trim(string str) { int finish = str.length() - 1; while (finish >= 0 && isspace(str[finish])) { finish--; } int start = 0; while (start <= finish && isspace(str[start])) { start++; } return str.substr(start, finish - start + 1);}/* * Implementation notes: readQuotedString and writeQuotedString * ------------------------------------------------------------ * Most of the work in these functions has to do with escape sequences. */static const string STRING_DELIMITERS = ",:)}]\n";bool stringNeedsQuoting(const string & str) { int n = str.length(); for (int i = 0; i < n; i++) { char ch = str[i]; if (isspace(ch)) return false; if (STRING_DELIMITERS.find(ch) != string::npos) return true; } return false;}void readQuotedString(istream & is, string & str) { str = ""; char ch; while (is.get(ch) && isspace(ch)) { /* Empty */ } if (is.fail()) return; if (ch == '\'' || ch == '"') { char delim = ch; while (is.get(ch) && ch != delim) { if (is.fail()) error("Unterminated string"); if (ch == '\\') { if (!is.get(ch)) error("Unterminated string"); if (isdigit(ch) || ch == 'x') { int base = 8; if (ch == 'x') base = 16; int result = 0; int digit = 0; while (ch != delim) { if (isdigit(ch)) { digit = ch - '0'; } else if (isalpha(ch)) { digit = toupper(ch) - 'A' + 10; } else { digit = base; } if (digit >= base) break; result = base * result + digit; if (!is.get(ch)) error("Unterminated string"); } ch = char(result); is.unget(); } else { switch (ch) { case 'a': ch = '\a'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'v': ch = '\v'; break; case '"': ch = '"'; break; case '\'': ch = '\''; break; case '\\': ch = '\\'; break; } } } str += ch; } } else { str += ch; int endTrim = 0; while (is.get(ch) && STRING_DELIMITERS.find(ch) == string::npos) { str += ch; if (!isspace(ch)) endTrim = str.length(); } if (is) is.unget(); str = str.substr(0, endTrim); }}void writeQuotedString(ostream & os, const string & str, bool forceQuotes) { if (!forceQuotes && stringNeedsQuoting(str)) forceQuotes = true; if (forceQuotes) os << '"'; int len = str.length(); for (int i = 0; i < len; i++) { char ch = str.at(i); switch (ch) { case '\a': os << "\\a"; break; case '\b': os << "\\b"; break; case '\f': os << "\\f"; break; case '\n': os << "\\n"; break; case '\r': os << "\\r"; break; case '\t': os << "\\t"; break; case '\v': os << "\\v"; break; case '"': os << oct << "\\" << (int(ch) & 0xFF); break; case '\\': os << "\\\\"; break; default: if (isprint(ch)) { os << ch; } else { ostringstream oss; oss << oct << (int(ch) & 0xFF); os << "\\" << oss.str(); } } } if (forceQuotes) os << '"';}
- C类型字符串,来自于C编程语言
- C++类型string,C++实现的库
在C++中,尽可能的使用string类型。
对于string s = "Nubian " + "ibex";
这些字符串是C风格的,C风格的字符串是不支持+操作的,该表达式编译不通过。改为如下:
string s = string("Nubian ") + "ibex";
现在显式的转换C风格的字符串为C++类型的字符串,这样该代码是合法的。 二、字符串中的递归操作
1.对一个字符串进行逆序操作
递归的对字符串进行逆序操作,如下示意图所示:
代码实现如下:
/* File: reverse.cpp * * Code to recursively reverse a string. */#include2.回文(palindrome)#include #include "simpio.h"using namespace std;string reverseString(string line);int main() { string line = getLine("Enter a string: "); cout << reverseString(line) << endl;}/* Returns the reverse of the indicated string. */string reverseString(string line) { /* If the string is empty, it's its own reverse */ if (line == "") { return ""; } /* Otherwise, reverse all but the first character, then tack * on the first character. */ else { return reverseString(line.substr(1)) + line[0]; }}
回文就是给定的字符串是对称的。
递归的判断给定的字符串是否是回文,示意图如下:
代码实现如下:
/* File: palindrome.cpp * * A program that reads a file of English words, then prints out all * the palindromic words. */#include3.C++中从File中读取数据#include #include #include "simpio.h"using namespace std;bool isPalindrome(string text);int main() { /* Open the file for reading. We really should check whether * the file is open before proceeding. */ string file = "dictionary.txt"; ifstream input(file.c_str()); /* Read each line of the file and print out those that are palindromes. */ string line; while (getline(input, line)) { if (isPalindrome(line)) { cout << line << endl; } } return 0;}/* Returns whether the given string is a palindrome. */bool isPalindrome(string text) { /* All characters of length 0 or length 1 are guaranteed to * be palindromes. */ if (text.length() <= 1) { return true; } /* If the first and last character of the string aren't the same, * the string cannot be a palindrome. */ else if (text[0] != text[text.length() - 1]) { return false; } /* Otherwise, this string is a palindrome precisely when the middle * characters are a palindrome. */ else { return isPalindrome(text.substr(1, text.length() - 2)); }}
既然我们知道了如何操作字符串了,那么我们开始从外部文件中读取数据来处理。
在C++中,文件读取使用ifstream类来进行处理。必须包含头文件#include <fstream>来使用ifstream。
1)逐行读取
ifstream类通过使用getline函数从文件中读取一行
getline(file, str);典型的读取文件中各行的循环如下所示:
string line;while(getline(file, line)){ /* ...process line... */}回文的实现代码使用了文件的读取。
读取格式化的数据
从文件中读取格式化的数据可以通过使用流提取操作符:file>>variable
可以读取任何原始类型和字符串
当读取字符串时,在换行符或空格处即停止。
典型的读取格式化数据循环如下:
type val;while(file >> val){ /* ... process val... */}4.C++中参数传递
在C++中,有两种方法传递一个参数给一个函数:
- 传值方式:参数通过拷贝传给一个函数。void myFunction(int x);
- 引用方式:传递给函数的变量在函数中是可以改变的。void myFunction(int &x)
举例:
int main(){ int x = 10; int y = 20; //here: x = 10, y = 20 sum(x, y); //here: x = 10, y = 20 swap(x, y); //here: x = 20, y = 10 cout << x << " " << y << endl; return 0;}//Pass by referencevoid swap(int &x, int &y){ int temp = x; x = y; y = temp;}//Pass by valuevoid printSum(int x, int y){ x += y; cout << x << endl;}