【stanford C++】字符串(String)与流(Stream)

字符串(String)与流(Stream)
一、C++中字符串(String)

字符串(String):就是(可能是空的)字符序列。
C++中的字符串在概念上和Java中的字符串类似。

C++字符串用string类型来表示。在使用string类型之前,必须在程序中包含如下头文件
#include <string>

可以通过调用如下方法:
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

#include <iostream>
#include <string>

/*
 * Function: integerToString
 * Usage: string s = integerToString(n);
 * -------------------------------------
 * Converts an integer into the corresponding string of digits.
 * For example, calling <code>integerToString(123)</code> returns
 * the string <code>"123"</code>.
 */

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,
 * <code>stringToInteger</code> calls <code>error</code> 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, calling <code>realToString(23.45)</code> returns
 * the string <code>"23.45"</code>.
 */

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, <code>stringToReal</code>
 * calls <code>error</code> 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)) ...
 * ----------------------------------------
 * Returns <code>true</code> if <code>s1</code> and <code>s2</code> are
 * equal discounting differences in case.
 */

bool equalsIgnoreCase(std::string s1, std::string s2);

/*
 * Function: startsWith
 * Usage: if (startsWith(str, prefix)) ...
 * ---------------------------------------
 * Returns <code>true</code> if the string <code>str</code> 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)) ...
 * -------------------------------------
 * Returns <code>true</code> if the string <code>str</code> 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.
 */

template <typename ValueType>
void 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 <typename ValueType>
void readGenericValue(std::istream & is, ValueType & value) {
   is >> value;
}

template <>
inline void readGenericValue(std::istream & is, std::string & value) {
   readQuotedString(is, value);
}


#endif

strlib.c的代码如下:
/*
 * File: strlib.cpp
 * ----------------
 * This file implements the strlib.h interface.
 */

#include <cctype>
#include <iostream>
#include <sstream>
#include "error.h"
#include "strlib.h"
using namespace std;

/* Function prototypes */

/*
 * Implementation notes: numeric conversion
 * ----------------------------------------
 * These functions use the <sstream> 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编程语言
  • 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.
 */
#include <iostream>
#include <string>
#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];
	}
}

2.回文(palindrome)
回文就是给定的字符串是对称的。
递归的判断给定的字符串是否是回文,示意图如下:

代码实现如下:
/* File: palindrome.cpp
 *
 * A program that reads a file of English words, then prints out all
 * the palindromic words.
 */
#include <iostream>
#include <string>
#include <fstream>
#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));
	}
}

3.C++中从File中读取数据

既然我们知道了如何操作字符串了,那么我们开始从外部文件中读取数据来处理。
在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 reference
void swap(int &x, int &y)
{
	int temp = x;
	x = y;
	y = temp;
}

//Pass by value
void printSum(int x, int y)
{
	x += y;
	cout << x << endl;
}



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值