The easiest way to figure out if the comma is in the correction position is to go backwards (starting from the rightmost character) within the string.
The reason why this is easier is that if you were to start from the leftmost character and go forward, when you encounter a ,
, you don't really know at that point whether that comma is in a valid position. You will only know until later on within the iteration process.
On the other hand, when you go from right-to-left, you know that if you encounter a comma, that comma is in a valid position -- there is no need to wait until you've gone further in the string to determine if the comma is valid.
To do this, it takes an adjustment in the loop to go backwards, and an additional counter to track the current group of 3 digits, since a comma can only occur after a group of 3 digits has been processed.
This is an untested example (except for the simple tests in main
):
#include <string>
#include <cctype>
#include <iostream>
bool commas(std::string input)
{
// if the string is empty, return false
if (input.empty())
return false;
// this keeps count of the digit grouping
int counter = 0;
// loop backwards
for (int z = static_cast<int>(input.size()) - 1; z >= 0; --z)
{
// check if the current character is a comma, and if it is in
// position where commas are supposed to be
if (counter == 3)
{
if (input[z] != ',')
return false;
// reset counter to 0 and process next three digits
counter = 0;
}
else
// this must be a digit, else error
if (input[z] == ',')
return false;
else
// go to next digit in group of 3
++counter;
}
// the first character must be a digit.
return isdigit(static_cast<unsigned char>(input[0]));
}
int main()
{
std::string tests[] = { "123,,345",
"123,345",
"123,345,678",
"12,345",
"1223,345",
",123,345",
"1",
"",
"65,00",
"123"};
const int nTests = sizeof(tests) / sizeof(tests[0]);
for (int i = 0; i < nTests; ++i)
std::cout << tests[i] << ": " << (commas(tests[i]) ? "good" : "no good") << "\n";
}
Output:
123,,345: no good
123,345: good
123,345,678: good
12,345: good
1223,345: no good
,123,345: no good
1: good
: no good
65,00: no good
123: good
The way this works is simple -- we just increment a counter and see if the current position we're looking at (position z
) in the string is a position where a comma must exist.
The count simply counts each group of 3 digits -- when that group of 3 digits has been processed, then the next character (when going backwards) must be a comma, otherwise the string is invalid. We also check if the current position is where a comma cannot be placed.
Note that at the end, we need to check for invalid input like this:
,123
This is simply done by inspecting the first character in the string, and ensuring it is a digit.