C++ 测试C++;98字符串是科学记数法中的数字
我有一个C++ 测试C++;98字符串是科学记数法中的数字,c++,c++03,C++,C++03,我有一个字符串变量,它可以是以下三种情况之一: 数 科学记数法中的数字 正文 在案例1和案例3中,我不想做任何事情并传递数据。但在第二种情况下,我需要把它转换成一个正则数。如果我总是简单地将变量转换为一个正则数,那么当它包含实际文本时,它将变为“0”。所以我需要知道字符串是否是科学记数法中的数字。显然,肮脏的答案是这样一种算法: .123 .123E3 123. 123.E+3 只要看到数字,就可以遍历字符串。如果遇到的第一个字母是“e”或“e”,后面跟着“+”或“-”或更多的数字,那么它就是
字符串
变量,它可以是以下三种情况之一:
.123
.123E3
123.
123.E+3
只要看到数字,就可以遍历字符串。如果遇到的第一个字母是“e”或“e”,后面跟着“+”或“-”或更多的数字,那么它就是科学记数法中的数字,否则它只是一个常规数字或文本
但是我认为在C++98中有更好的方法来实现这一点(没有boost)。有什么内置的方法可以帮助您吗?即使它只是一个尝试/抓住的东西
编辑问题已关闭,因为它被假定为家庭作业。这不是家庭作业。因此,它应该重新开放。另外,为了澄清,由于技术限制,我不得不使用C++98
根据我最初的想法,我画了一个建议的有限状态automota(“other”表示没有为给定状态指定的所有字符)。我相信这是正确的
应接受的一些示例输入:
1.453e-8
0.05843E5
8.43e6
5.2342E-7
应失败的一些示例输入:
hello
03HX_12
8432
8432E
e-8
fail-83e1
您的自动机的主要问题在于规格/要求方面:它要求小数点两侧有一个或多个数字,拒绝这样的输入:
.123
.123E3
123.
123.E+3
目前尚不清楚是否应拒绝这些建议;一些编程语言允许这些形式。拒绝没有尾数的东西可能是个好主意,不过:
.
.E+03
如果这不是故意的,而是遗漏了需求,那么必须调整状态机。因为现在元素是可选的,所以修复状态机的最简单方法是让它成为非确定性(NFA图)。这只会带来不必要的困难。因为您最终还是要编写代码,所以使用特别的过程代码最容易处理这个问题
与传统自动机的形式化处理相比,特殊过程代码的优势在于前瞻性:它可以像自动机一样在不消耗输入的情况下偷看下一个字符,并且基于前瞻性,它可以决定是否消耗该字符,而不依赖于在多个代码路径之间的转换。换句话说,伪代码:
have_digits_flag = false
while (string begins with a digit character) {
have_digits_flag = true
consume digit character
}
if (!string begins with a decimal point)
goto bad;
consume decimal point
while (string begins with digit) {
consume digit
have_digits_flag = true;
}
if (!have_digits_flag)
goto bad; // we scanned just a decimal point not flanked by digits!
if (string begins with e or E) {
consume character
if (string begins with + or -)
consume character
if (!string begins with digit)
goto bad;
while (string begins with digit)
consume character
}
if (string is empty)
return true;
// oops, trailing junk
bad:
return false;
“stringstart with”操作显然必须是安全的,以防字符串为空。空字符串根本不满足任何字符的“字符串以开头”谓词
如何实现“消费角色”取决于您。您可以从std::string
对象中删除一个字符,或者在其中移动一个迭代器以指示输入位置
这种方法的缺点是效率不高。在这里,这也许无关紧要,但一般来说,临时代码会遇到一个问题,即它会针对前瞻性测试多个案例。在一个复杂的模式中,这些可能是很多的。一个表驱动的自动机永远不需要第二次查看任何输入符号。使用一个非常好的状态机来解析数字。它不太严格,但不接受像“e”或“-.e2”这样的垃圾
它是:
- “-”,或
- 没什么
- “0”,或
- (一位数字[1-9],后跟零或多个[0-9])
- (“.”后跟一个或多个[0-9]),或
- 没什么
- ((('e'或'e'),后跟(+'或'-'或无),后跟零或更多[0-9]),或
- 没什么
模板
静态输入提取器编号(变量和结果、输入st、输入en);
模板
inputitJSONParser::extractNumber(变量和结果、inputitST、inputitEN)
{
如果(st==en)
parseError(“输入结束时的预期数字”);
向量文本;
自动接受=[&]{
如果(st==en)
parseError(“输入结束时的预期数字”);
text.emplace_back(*st++);
};
//-?(?:0 |[1-9][0-9]*)(?:\[0-9]+)(?:[eE][+-]?[0-9]+)?
//A、B、C、D、E
bool isFloatingPoint=false;
如果(*st='-'))
{
//A
接受();
}
如果(*st==“0”)
{
//B
接受();
}
否则如果(标准::isdigit(*st,cLocale))
{
//C
做
{
接受();
}
while(st!=en&std::isdigit(*st,cLocale));
}
其他的
{
解析错误(“无效数字”);
}
如果(st!=en&&*st=='。)
{
接受();
isFloatingPoint=true;
//D
while(st!=en&std::isdigit(*st,cLocale))
接受();
}
如果(st!=en&(*st=='E'| |*st=='E'))
{
isFloatingPoint=true;
//E
接受();
if(st!=en&(*st='+'| |*st=='-'))
接受();
if(st==en | |!std::isdigit(*st,cLocale))
解析错误(“无效数字”);
while(st!=en&std::isdigit(*st,cLocale))
接受();
}
文本。向后放置(0);
如果(isFloatingPoint)
赋值(std::atof(text.data());
其他的
赋值(std::int64_t(std::atol(text.data()));
返回st;
}
我不得不稍微调整一下,因为周围的实现确保st
不会等于en
on
template<typename InputIt,
typename V = typename
std::iterator_traits<InputIt>::value_type>
static InputIt extractNumber(Variant& result, InputIt st, InputIt en);
template<typename InputIt, typename V>
InputIt JsonParser::extractNumber(Variant& result, InputIt st, InputIt en)
{
if (st == en)
parseError("Expected number at end of input");
std::vector<V> text;
auto accept = [&] {
if (st == en)
parseError("Expected number at end of input");
text.emplace_back(*st++);
};
// -?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?
// A B C D E
bool isFloatingPoint = false;
if (*st == '-')
{
// A
accept();
}
if (*st == '0')
{
// B
accept();
}
else if (std::isdigit(*st, cLocale))
{
// C
do
{
accept();
}
while (st != en && std::isdigit(*st, cLocale));
}
else
{
parseError("Invalid number");
}
if (st != en && *st == '.')
{
accept();
isFloatingPoint = true;
// D
while (st != en && std::isdigit(*st, cLocale))
accept();
}
if (st != en && (*st == 'E' || *st == 'e'))
{
isFloatingPoint = true;
// E
accept();
if (st != en && (*st == '+' || *st == '-'))
accept();
if (st == en || !std::isdigit(*st, cLocale))
parseError("Invalid number");
while (st != en && std::isdigit(*st, cLocale))
accept();
}
text.emplace_back(0);
if (isFloatingPoint)
result.assign(std::atof(text.data()));
else
result.assign(std::int64_t(std::atoll(text.data())));
return st;
}
bool is_valid(std::string src){
std::stringstream ss;
ss << src;
double d=0;
ss >> d;
if (ss){
return true;
}
else{
return false;
}
}
bool is_scientific_notation(string input) {
int state = 0;
for (string::size_type i = 0; i < input.size(); i++) {
char character = input.at(i);
//cout << character << endl;
switch(state) {
case 0: {
// state 0: accept on '. or' '-' or digit
if (character == '.') {
state = 3;
} else if (character == '-') {
state = 1;
} else if (isdigit(character)) {
state = 2;
} else {
goto reject; // reject
}
break;
}
case 1: {
// state 1: accept on '. or digit
if (character == '.') {
state = 3;
} else if (isdigit(character)) {
state = 2;
} else {
goto reject; // reject
}
break;
}
case 2: {
// state 2: accept on '.' or 'e' or 'E' digit
if (character == '.') {
state = 4;
} else if ((character == 'e') || (character == 'E')) {
state = 5;
} else if (isdigit(character)) {
state = 2;
} else {
goto reject; // reject
}
break;
}
case 3: {
// state 3: accept on digit
if (isdigit(character)) {
state = 4;
} else {
goto reject; // reject
}
break;
}
case 4: {
// state 4: accept on 'e' or 'E' or digit
if ((character == 'e') || (character == 'E')) {
state = 5;
} else if (isdigit(character)) {
state = 4;
} else {
goto reject; // reject
}
break;
}
case 5: {
// state 5: accept on '+' or '-' or digit
if ((character == '+') || (character == '-')) {
state = 6;
} else if (isdigit(character)) {
state = 6;
} else {
goto reject; // reject
}
break;
}
case 6: {
// state 6: accept on digit
if (isdigit(character)) {
state = 6;
} else {
goto reject; // reject
}
break;
}
}
}
if (state == 6) {
return true;
} else {
reject:
return false;
}
}
// is_scientific_notation should return true
cout << ((is_scientific_notation("269E-9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("269E9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("269e-9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("1.453e-8")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("8.43e+6")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("5.2342E-7")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation(".2342E-7")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("8.e+2")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("-853.4E-2")) ? ("pass") : ("fail")) << endl;
// is_scientific_notation should return false
cout << ((is_scientific_notation("hello")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("03HX_12")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("8432")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("8432E")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("fail-83e1")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation(".e8")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("E-8")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("2e.2")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("-E3")) ? ("fail") : ("pass")) << endl;
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass