C++技巧:字符串操作(第二部分)

ZDNet软件频道 时间:2002-12-31 作者:BUILDER.COM |  我要评论()
本文关键词:cpptips
在前一节,我们介绍了StringEscaper类,这一个类允许你在字符串操作时忽略或不忽略指定的字符。现在,让我们来看看如何把字符串写入任意的文件流并正确地从文件流中读出来。

在前一节,我们介绍了StringEscaper类,这一个类允许你在字符串操作时忽略或不忽略指定的字符。现在,让我们来看看如何把字符串写入任意的文件流并正确地从文件流中读出来。

PersistString类允许你把任意字符串写入一文件流,并确保你正确地读出来,这一字符串可以包含很多行或很多字符。为了实现这一目的,它采用双引号来包围指定的字符串,然后通过StringEscaper类中的函数来操作这一字符串。这样,当字符串要读回来时,你就知道如何去读取它(可查看末尾的引号)。程序员必须清楚这一过程。

构建一个PersistString对象有两种方法:

  • 通过StringEscaper类来传递:这一方法能够让你进一步地忽略字符串中的字符。例如,为了把字符串写在同一行中,你可以在操作中忽略回车键。
  • 使用缺省的StringEscaper:可以通过加两个双引号来忽略双引号(例如,"me"可以写成"""me""")。

作为一个功能强大的函数,你可以很方便地使用LinePersistString类,这一类使用缺省的字符忽略,可以在同一行中忽略地操作指定的字符。同时,你也可以在同一行写入多个字符串,甚至在同一行写入所有的字符串。

这里提供了PersistString和LinePersistString的代码:

#include "StringEscaper.h"

// PersistentString.h
#include <sstream>

const char_type PERSISTENT_STRING_DELIMETER = '"';

// behaves *** exactly *** like a string.
// however, no matter what it contains, it can safely
// be written to a stream/ read from a stream

class PersistentString
public string_type
{
static EscapeStringInfo s_DefaultEscapeInfos;
public:
PersistentString()
m_escaper( s_DefaultEscapeInfos)
{}
explicit PersistentString( const char_type * strFrom)
m_escaper( s_DefaultEscapeInfos), string_type( strFrom)
{}
explicit PersistentString( const string_type & strFrom)
m_escaper( s_DefaultEscapeInfos),
string_type( strFrom)
{}
PersistentString( const EscapeStringInfo & escapeInfo)
m_escaper( escapeInfo)
{
//we need to escape the quotes
m_escaper.AddEscapeChar( PERSISTENT_STRING_DELIMETER, PERSISTENT_STRING_DELIMETER);
}

PersistentString & operator=( const string_type & strFrom)
{
assign( strFrom);
return *this;
}
PersistentString & operator=( const char_type * strFrom)
{
assign( strFrom);
return *this;
}
template< class CharType, class CharTraits>
void write_to_stream( std::basic_ostream< CharType, CharTraits> & streamOut) const
{
string_type strEscaped = *this;
m_escaper.escape( strEscaped);
// surround it with delimeters
streamOut << PERSISTENT_STRING_DELIMETER << strEscaped << PERSISTENT_STRING_DELIMETER;
}
template< class CharType, class CharTraits>
void read_from_stream ( std::basic_istream< CharType, CharTraits> & streamIn)
{
std::basic_stringstream< char_type> streamBuffer;
// ignore any leading spaces
bool bContinue = true;
char_type chCurrent = 0;
while ( bContinue && streamIn.good())
{
streamIn.get( chCurrent);
if ( !isspace( chCurrent))
{ break; }
}
if ( chCurrent == PERSISTENT_STRING_DELIMETER)
{
char_type chEscapeChar = m_escaper.GetEscapeChar();
char_type chPrevious = 0;
bool bReadCorrectly = false;
while ( streamIn.good())
{
streamIn.get( chCurrent);
if ( chCurrent == PERSISTENT_STRING_DELIMETER)
{
if ( chEscapeChar == PERSISTENT_STRING_DELIMETER)
{
// we escape using the delimeter (ex: '""')
char_type chNext = 0;
streamIn.get( chNext);
if( chNext == PERSISTENT_STRING_DELIMETER)
{
//escaped delimeter
streamBuffer << chCurrent << chNext;
}
else
{
//reached end of string
if ( streamIn.good())
{
streamIn.putback( chNext);
}
bReadCorrectly = true;
break;
}
}
else
{
// escape char is not the delimeter
if( chPrevious == chEscapeChar)
{
//escaped delimeter
streamBuffer << chCurrent;
}
else
{
// reached end of string
bReadCorrectly = true;
break;
}
}
}
else
{
// normal character
streamBuffer << chCurrent;
}
chPrevious = chCurrent;
}
if ( bReadCorrectly)
{
// read the string
assign( streamBuffer.str());
// unescape t
m_escaper.unescape( *this);
}
else
{
// problems at reading _ (most likely reached end of stream, but
// we could read the whole string)

streamIn.setstate( std::ios_base::failbit);
}
}
else
{
// we read invalid characters -_ we should have read Start of String ('"') char.
streamIn.setstate( std::ios_base::failbit);
}
}
private:
StringEscaper m_escaper;
};
template< class CharType, class CharTraits>
std::basic_ostream< CharType, CharTraits> & operator<_ <( std::basic_ostream< CharType, CharTraits>_ & streamOut, const PersistentString & value)
{
value.write_to_stream< CharType, CharTraits>( streamOut);
return streamOut;
}
template< class CharType, class CharTraits>
std::basic_istream< CharType, CharTraits> & operator>>( std::basic_istream< CharType, CharTraits> _ & streamIn, PersistentString & value)
{
value.read_from_stream< CharType, CharTraits>( streamIn);
return streamIn;
}
// it's persistent; it can be part of an object _ which has to be persisted on a line
// (this means the LinePersistentString will be a part of this line)

class LinePersistentString
public PersistentString
{
public:
LinePersistentString()
PersistentString( StringEscaper::DEFAULT_ESCAPE_INFOS)
{}
explicit LinePersistentString( const char_type * strFrom)
PersistentString( StringEscaper::DEFAULT_ESCAPE_INFOS)
{ ( *this) = strFrom; }

explicit LinePersistentString( const string_type & strFrom)
PersistentString( StringEscaper::DEFAULT_ESCAPE_INFOS)
{ ( *this) = strFrom; }
LinePersistentString & operator=_ ( const string_type & strFrom)
{
assign( strFrom);
return *this;
}
LinePersistentString & operator=( const char_type * strFrom)
{
assign( strFrom);
return *this;
}
};
template< class CharType, class CharTraits>
std::basic_ostream< CharType, CharTraits> & _ operator<<( std::basic_ostream< CharType, CharTraits>_ & streamOut, const LinePersistentString & value)
{
value.write_to_stream< CharType, CharTraits>( streamOut);
return streamOut;
}
template< class CharType, class CharTraits>
std::basic_istream< CharType, CharTraits> &_ operator>>( std::basic_istream< CharType, _ CharTraits> & streamIn, LinePersistentString & value)
{
value.read_from_stream< CharType, CharTraits>( streamIn);
return streamIn;
}
// PersistentString.cpp
// anonymous namespace

namespace
{
EscapeStringChar aDefaultPersistentEscapes[] =
{
{ PERSISTENT_STRING_DELIMETER, PERSISTENT_STRING_DELIMETER },
{ 0, 0 }
};
}
EscapeStringInfo PersistentString::s_DefaultEscapeInfos =
{ PERSISTENT_STRING_DELIMETER, aDefaultPersistentEscapes };


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134