Ale*_*tke 3 c++ stringstream c++11
这似乎微不足道,但我似乎无法解决这个问题.我有格式的STL字符串2013 336 (02 DEC) 04(04小时在哪里,但这是无关紧要的).我想提取月份的日期(02在示例中)和月份以及小时.
我试图干净利落地避免例如在括号中拆分字符串,然后使用子字符串等.理想情况下,我想使用a stringstream并将其重定向到变量.我现在得到的代码是:
int year, dayOfYear, day;
std::string month, leftParenthesis, rightParenthesis;
std::string ExampleString = "2013 336 (02 DEC) 04";
std::istringstream yearDayMonthHourStringStream( ExampleString );
yearDayMonthHourStringStream >> year >> dayOfYear >> leftParenthesis >> day >> month >> rightParenthesis >> hour;
Run Code Online (Sandbox Code Playgroud)
它提取year并且dayOfYear好了2013,336但事情开始变得糟糕.day是0,month和空字符串,和hour843076624.
leftParenthesis是(02这样它包含day但当我尝试省略leftParenthesis变量时,重定向yearDayMonthHourStringStream流day也是0.
关于如何处理这个问题的任何想法?我不知道正则表达式(但是),不可否认,我不知道我现在是否能够学会它们(时间).
编辑 好的,我知道了.虽然这就像我可以用正则表达式让生活变得那么容易的第十亿次,所以我想是时候了.无论如何,有用的是:
int year, dayOfYear, day, month, hour, minute, revolution;
std::string dayString, monthString;
yearDayMonthHourStringStream >> year >> dayOfYear >> dayString >> monthString >> hour;
std::string::size_type sz;
day = std::stod( dayString.substr( dayString.find("(")+1 ), &sz ); // Convert day to a number using C++11 standard. Ignore the ( that may be at the beginning.
Run Code Online (Sandbox Code Playgroud)
这仍然需要处理monthString,但我需要将其改为数字,所以这不是一个巨大的劣势.不是你能做的最好的事情(正则表达式)但是工作并且不是太脏.据我所知,也是模糊的便携式,希望不会停止使用新的编译器.但是,谢谢大家.
显而易见的解决方案是使用正则表达式(
std::regex在C++ 11或boost::regexC++ 11之前).只需捕获您感兴趣的群组,并std::istringstream在必要时使用
它们进行转换.在这种情况下,
std::regex re( "\\s*\\d+\\s+\\d+\\s*\\((\\d+)\\s+([[:alpha:]]+))\\s*(\\d+)" );
Run Code Online (Sandbox Code Playgroud)
应该做的伎俩.
正则表达式非常简单; 学习它们所花费的时间比实施任何替代解决方案要少.
对于替代解决方案,您可能希望逐个字符地读取行,将其分解为标记.沿线的东西:
std::vector<std::string> tokens;
std::string currentToken;
char ch;
while ( source.get(ch) && ch != '\n' ) {
if ( std::isspace( static_cast<unsigned char>( ch ) ) ) {
if ( !currentToken.empty() ) {
tokens.push_back( currentToken );
currentToken = "";
}
} else if ( std::ispunct( static_cast<unsigned char>( ch ) ) ) {
if ( !currentToken.empty() ) {
tokens.push_back( currentToken );
currentToken = "";
}
currentToken.push_back( ch );
} else if ( std::isalnum( static_cast<unsigned char>( ch ) ) ) {
currentToken.push_back( ch );
} else {
// Error: illegal character in line. You'll probably
// want to throw an exception.
}
}
if ( !currentToken.empty() ) {
tokens.push_back( currentToken );
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,一系列字母数字字符是一个标记,任何单个标点字符也是如此.您可以更进一步,确保令牌全部为alpha或所有数字,并且可能重新组合标点符号序列,但这似乎足以解决您的问题.
获得令牌列表后,您可以进行任何必要的验证(在正确的位置括号等),并转换您感兴趣的令牌,如果他们需要转换.
编辑:
FWIW:我一直在尝试使用auto加上lambda作为定义嵌套函数的方法.我的思绪并没有弥补是否是一个好主意:我并不总能找到可读的结果.但在这种情况下:
auto pushToken = [&]() {
if ( !currentToken.empty() ) {
tokens.push_back( currentToken );
currentToken = "";
}
}
Run Code Online (Sandbox Code Playgroud)
就在循环之前,则更换所有的if用
pushToken().(或者你可以创建一个数据结构
tokens,currentToken和pushToken成员函数.这工作,即使在预C++ 11).
编辑:
最后一句话,因为OP似乎只想用这个来做std::istream:解决方案就是添加一个MustMatch操纵器:
class MustMatch
{
char m_toMatch;
public:
MustMatch( char toMatch ) : m_toMatch( toMatch ) {}
friend std::istream& operator>>( std::istream& source, MustMatch const& manip )
{
char next;
source >> next;
// or source.get( next ) if you don't want to skip whitespace.
if ( source && next != m_toMatch ) {
source.setstate( std::ios_base::failbit );
}
return source;
}
}
Run Code Online (Sandbox Code Playgroud)
正如@Angew指出的那样,你>>几个月也需要一个; 通常,几个月会被表示为一个类,所以你要重载>>:
std::istream& operator>>( std::istream& source, Month& object )
{
// The sentry takes care of skipping whitespace, etc.
std::ostream::sentry guard( source );
if ( guard ) {
std::streambuf* sb = source.rd();
std::string monthName;
while ( std::isalpha( sb->sgetc() ) ) {
monthName += sb->sbumpc();
}
if ( !isLegalMonthName( monthName ) ) {
source.setstate( std::ios_base::failbit );
} else {
object = Month( monthName );
}
}
return source;
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以在此处引入许多变体:月份名称可以限制为最多3个字符,例如(通过制作循环条件monthName.size() < 3 &&
std::isalpha( sb->sgetc() )).但是,如果你有个以任何方式在你的代码打交道,写一个Month类及其
>>与<<运营商是你必须做的反正迟早.
然后像:
source >> year >> dayOfYear >> MustMatch( '(' ) >> day >> month
>> MustMatch( ')' ) >> hour;
if ( !(source >> ws) || source.get() != EOF ) {
// Format error...
}
Run Code Online (Sandbox Code Playgroud)
就是这一切.(像这样使用操纵器是另一种值得学习的技术.)