How would I detect an invalid operator

How would I detected an invalid argument like these.
+212+21-2
12+3
+3-1
ect
I tried counting the amount of operators but it didnt work, I also couldnt find anything online, so what would be the best approach. I already tried using a double for loop to count the amount of each operator but it didnt work.

I have marked where the validation checker is.

I tried to put my code in but its too large

Last edited on
Context please!

Invalid "arguments" for what? I mean, if someone asked you to "input a mathematical expression" then they would be perfectly valid responses.

You haven't "marked where the validation checker is".
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
for (int i = 1; i < 2; i++)
	{
		int x = 0;
		for (int j = 0; j < strlen(argv[i]); j++)
		{
			int L = 0;
			if (isdigit(argv[i][j]) || argv[i][j] == '.' || argv[i][j] == '-' || argv[i][j] == '+' || argv[i][j] == 'e' || argv[i][j] == ',' || argv[i][j] == 'E')
			{
				w = w + 1;
				cout << argv[i][j];
				// count the amount of operators
				int x2 = 0;
				
				//Checks '.'
				if (argv[i][j] == '.')
				{
					x = x + 1;
					j = j + 1;
					if (x > 1)			// if there is more than one '.'
					{
						cout << "X" << endl;
						return 0;
					}
					if (argv[i][j] == 'e')		// checks that there isnt an e after the '.' e.g 1.e+2
					{
						cout << "X" << endl;
						return 0;
					}
					else
					{
						j = j - 1;
					}
				}
				if (argv[i][j] == 'e' || argv[i][j] == 'E')
				{
					L = L + 1;					  // checks for multiple e's (ee)
					j = j + 1;					  // checks for invalid e's (e-1)
					if (L > 1)
					{
						cout << "X" << endl;
						return 0;
					}
					if (argv[i][j] == '-')
					{
						j = j + 1;
						if (isdigit(argv[i][j]))		// checks that the power is valid, this is nonvalid 1.2e+-2
						{
							j = j - 1;
						}
						else
						{
							cout << "X" << endl;
							return 0;
						}
					}
					if (argv[i][j] == '+')
					{
						j = j + 1;
						if (isdigit(argv[i][j]))  //checks for double powers
						{
							j = j - 2;
						}
						else
						{
							cout << "X" << endl;
							return 0;
						}
					}
					else
					{
						j = j - 1;
					}
				}
				if (argv[i][j] == '-')								// | this is the beginning 
				{														   
					SUBCOUNT = SUBCOUNT + 1;
					if (SUBCOUNT > 1 && ADDCOUNT >= 1)
					{
						cout << "x" << endl;
						return 0;
					}
					j = j + 1;
					if (argv[i][j] == '-')
					{
						cout << "x" << endl;
						return 0;
					}
					else if (argv[i][j] == '+')
					{
						cout << "x" << endl;
						return 0;
					}
					else j = j - 1;

					if (argv[i][j] == '-')
					{
						cout << "x" << endl;
						return 0;
					}
					else if (argv[i][j] == '+')
					{
						cout << "x" << endl;
						return 0;
					}
					else j = j - 1;
				}
				if (argv[i][j] == '+')
				{
					ADDCOUNT = ADDCOUNT + 1;
					if (ADDCOUNT > 1 && SUBCOUNT >= 1)
					{
						cout << "x" << endl;
						return 0;
					}
					j = j + 1;
						
					if (argv[i][j] == '-')
					{
						cout << "x" << endl;
						return 0;
					}
					else if (argv[i][j] == '+')
					{
						cout << "x" << endl;
						return 0;
					}
					else j = j-1;

						return 0;
					if (SUBCOUNT > 1 && ADDCOUNT >= 1)
					{
						cout << "x" << endl;
					}
					j = j + 1;
					if (argv[i][j] == '-')
					{
						cout << "x" << endl;
						return 0;
					}
					else if (argv[i][j] == '+')
					{
						cout << "x" << endl;
						return 0;
					}
					else j = j - 1;
				}											// | this is the end
				if (argv[i][j] == ',')
				{
					string str = argv[1];

					for (int i = 0, len = str.size(); i < len; i++)
					{
						// check whether parsing character is punctuation or not 
						if (str[i] == ',')
						{
							str.erase(i--, 1);
							len = str.size();
							argval1 = atof(str.c_str());
							V2 = 1;
						}
					}

				}
				if (w == strlen(argv[i]))
				{
					//send command to OUSB board
					pinc = ReadPinC();
					if (pinc > 255)
					{
						cout << "Y" << endl;
						return 0;
					}
					if (pinc < 0)
					{
						cout << "Y" << endl;
						return 0;
					}
					if (V2 != 1)
					{
						argval1 = atof(argv[1]);
					}
				}

			}
			else
			{
				cout << "X" << endl;
				return 0;
			}
		}
	}


here is the snippet of my code i cant fit all of it in aa it goes over the character limit, I have 3 inputs that I need to compare and this code checks that the input via command arguments is 1 number( 1e+10, 1,000, 1.01, 0.001 ect) not +212+21-2, I used a counter but it isnt working. this is because I dont know how to test the infinite number of options there are.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

//======================================================================

bool getVal( string input, double &result )
{
   string remainder;
   stringstream ss( input );
   if ( !( ss >> result ) ) return false;        // Invalid (first item not a number)
   if ( ss >> remainder   ) return false;        // Invalid (something else on the line)
   return true;
}

//======================================================================

int main()
{
   string tests[] = { "  3.14159 ", "3.14159+23", "NaN", "3-12" };
   double result;

   for ( string s : tests )
   {
      bool OK = getVal( s, result );
      cout << "Test [" << s << "]:" << '\t' << "result: " << boolalpha << OK << '\t';
      if ( OK ) cout << result;
      cout << '\n';
   }
}


Test [  3.14159 ]:	result: true	3.14159
Test [3.14159+23]:	result: false	
Test [NaN]:	result: false	
Test [3-12]:	result: false	

Could you explain how it works exactly?
It calls the function getVal() to check each input string.

For that string to be valid it has to contain one number exactly.

The string is put into a stringstream, to isolate it from any other input and make sure that input failures on that stream do not leave other streams in a failed state. That stringstream acts like any other input stream (i.e. you can use the >> operator).

ss >> result will try to read a double from that stream (possibly with white space in front, which is allowed). It then tests the state of the stream
if ( !( ss >> result ) ) return false;
to check whether that read was successful.

The second test
if ( ss >> remainder ) return false;
makes sure there is nothing else (other than white space) left on the line.
Last edited on
Thank you so much for the help
1
2
3
4
5
6
7
8
bool getVal( string input, double &result )
{
   string remainder;
   stringstream ss( input );
   if ( !( ss >> result ) ) return false;        // Invalid (first item not a number)
   if ( ss >> remainder   ) return false;        // Invalid (something else on the line)
   return true;
}


This is a very inefficient way of performing std:string to double conversion - although it's simple code. If performance is an issue (probably isn't here), then using std::from_chars() is much more efficient than >> (or std::strtod() if your compiler doesn't yet support std::from_chars() for double/float).

Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <string>
#include <iostream>
#include <chrono>
#include <optional>
#include <sstream>
#include <type_traits>
#include <charconv>

template<typename T = int>
auto getVal(const std::string& input)
{
	static_assert(std::is_arithmetic_v<T>);

	std::string remainder;
	std::istringstream ss(input);
	T result;

	return (ss >> result) && !(ss >> remainder) ? std::optional<T>(result) : std::optional<T> {};
}

template<typename T = int>
[[nodiscard]] auto stonum(const std::string& str)
{
	static_assert(std::is_arithmetic_v<T>);

	constexpr char white[] {" \n\r\t"};
	bool ok {false};
	T num {};

	if (const auto fl {str.find_last_not_of(white)}; fl != std::string::npos) {
		const auto end {str.data() + fl + 1};
		const auto first {str.data() + str.find_first_not_of(white)};

		ok = (end != first) && (std::from_chars(first, end, num).ptr == end);
	}

	return ok ? std::optional<T>{num} : std::optional<T> {};
}


int main()
{
	const std::string pi = "     3.141592654  ";
	const unsigned long long iter = 5'000'000;

	const auto start1 = std::chrono::high_resolution_clock::now();

	double sum1 = 0;

	for (auto i = 0ULL; i < iter; ++i)
		sum1 += *getVal<double>(pi);

	const auto diff1 = std::chrono::high_resolution_clock::now() - start1;
	std::cout << "getVal " << std::chrono::duration<double, std::milli>(diff1).count() << " ms" << std::endl;

	const auto start2 = std::chrono::high_resolution_clock::now();

	double sum2 = 0;

	for (auto i = 0ULL; i < iter; ++i)
		sum2 += *stonum<double>(pi);

	const auto diff2 = std::chrono::high_resolution_clock::now() - start2;
	std::cout << "stonum " << std::chrono::duration<double, std::milli>(diff2).count() << " ms" << std::endl;
}


which on my laptop gives (VS 2019):


getVal 9896.39 ms
stonum 1211.66 ms


giving from_chars a performance improvement of about x8 over >> !

Even when using strtod(), see http://coliru.stacked-crooked.com/a/541af9db68e947d5

gives a performance improvement of about x4 over >>
Last edited on
Topic archived. No new replies allowed.