向前扫描%
,然后从那里解析内容。有一些古怪的,但不是那么糟糕(不知道你想把它做成inline
寿)。一般原则(我只是打字,因为我可能不是最好的代码形式 - 我没有试图编译它)。
inline void detect(const std::string& str, int& pos, int& n)
{
std::string::size_type last_pos = 0;
for(;;)
{
last_pos = str.find('%', last_pos)
if (last_pos == std::string::npos)
break; // Not found anythin.
if (last_pos == str.length()-1)
break; // Found stray '%' at the end of the string.
char ch = str[last_pos+1];
if (ch == '%') // double percent -> escaped %. Go on for next.
{
last_pos += 2;
continue;
}
pos = last_pos;
do
{
if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' ||
ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' ||
ch == '#' || ch == '\'')
{
last_pos++;
ch = str[last_pos+1];
}
else
{
// The below string may need appending to depending on version
// of printf.
if (string("AacdeEfFgGiopusxX").find(ch) != std::string::npos)
{
// Do something about invalid string?
}
n = last_pos - pos;
return;
}
} while (last_pos < str.length());
}
}
EDIT2:该位可能是更好的写法如下:
if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' ||
ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' ||
ch == '#' || ch == '\'') ...
if (string(".-*+lLzhtj #'").find(ch) != std::string::npos) ...
现在,那是你完成家庭作业。请回报你得到什么等级。
编辑:应该指出的是,一些常规printf将“拒绝”的东西被上面的代码所接受,例如, “%....... 5 ...... 6f”,“%5.8d”,“%-5-6d”或“%----- 09 --- 5555555555555555llllld”。如果你想要代码拒绝这些事情,这不是一个额外的工作量,只需要一点逻辑来检查“我们看过这个字符之前”的“检查特殊字符或数字”,并且在大多数情况下,只能允许一次特殊字符。正如评论所说,我可能错过了一些有效的格式说明符。如果你还需要应对“这个''''不允许'c''或这样的规则,它会变得更加棘手。但是,如果输入不是“恶意的”(例如,你想注释在哪一行上有格式说明符在工作的C源文件中),上述应该工作得很好。
为什么不只是抓住一个开源的'printf'实现,并将解析器位从其中解压出来? –
你不需要正则表达式。 printf格式说明符格式可以从左到右一次一个字符地解析。 –
如果您查看完整的['printf()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html)格式的POSIX规范,则会出现很多可能出现的字符在格式规范中。例如,'%100 $#+ - 0'* 101 $。* 102 $ llX'可能是'有效'的,尽管标志的某些组合没有意义。 –