我有一个要标记的字符串。它的格式为HHmmssff
,其中H
,m
,s
,f
是数字。
它应该被标记为四个2位数字,但我需要它也接受简写形式,如sff
,因此它将其解释为00000sff
。
我想使用boost::tokenizer
的{{1}},但它似乎仅适用于正偏移量,我希望它有点倒退。
好的,一个想法是用左边的零填充字符串,但也许社区提出了一些 uber -smart。 ;)
修改 其他要求刚刚发挥作用。
智能解决方案的基本需求是处理所有情况,例如offset_separator
,f
,ssff
等,但也接受更完整的时间表示法,例如{{1用它的简写形式,例如mssff
甚至HH:mm:ss:ff
(这个应该被解释为s:ff
)。
如果字符串以s:
结尾,我显然可以用两个零填充它,然后去除所有分隔符,只留下数字并用精神解析结果字符串。
但是,如果有一种方法可以使偏移标记器从字符串的末尾返回(偏移-2,-4,-6,-8)并且词法上将数字转换为s:00
秒。
答案 0 :(得分:1)
我一直在传播BNF表示法。如果您可以写下定义问题的语法,您可以轻松地将其转换为Boost.Spirit解析器,它将为您完成。
TimeString := LongNotation | ShortNotation
LongNotation := Hours Minutes Seconds Fractions
Hours := digit digit
Minutes := digit digit
Seconds := digit digit
Fraction := digit digit
ShortNotation := ShortSeconds Fraction
ShortSeconds := digit
编辑:附加约束
VerboseNotation = [ [ [ Hours ':' ] Minutes ':' ] Seconds ':' ] Fraction
答案 1 :(得分:0)
我想到了正则表达式。像"^0*?(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)$"
boost::regex
这样的东西。子匹配将为您提供数字值。不应该难以采用您的其他格式与数字之间的冒号(请参阅sep61.myopenid.com的答案)。 boost::regex
是最快的正则表达式解析器之一。
答案 2 :(得分:0)
回应评论“不要故意成为一个表演狂,但这个解决方案涉及一些字符串复制(输入是一个const& std :: string)”。
如果你真的非常关心性能而不能使用像正则表达式那样的大型旧库,那么不会冒BNF解析器的风险,不要以为std :: string :: substr会避免副本with allocation(因此不能使用STL字符串函数),甚至不能将字符串字符复制到缓冲区和左键字符串中,并带有'0'字符:
void parse(const string &s) {
string::const_iterator current = s.begin();
int HH = 0;
int mm = 0;
int ss = 0;
int ff = 0;
switch(s.size()) {
case 8:
HH = (*(current++) - '0') * 10;
case 7:
HH += (*(current++) - '0');
case 6:
mm = (*(current++) - '0') * 10;
// ... you get the idea.
case 1:
ff += (*current - '0');
case 0: break;
default: throw logic_error("invalid date");
// except that this code goes so badly wrong if the input isn't
// valid that there's not much point objecting to the length...
}
}
但从根本上说,只是初始化那些int变量几乎与将字符串复制到带填充的char缓冲区一样多,所以我不希望看到任何显着的性能差异。因此,我实际上并没有在现实生活中推荐这种解决方案,只是作为过早优化的练习。