Home > front end >  Reading a line from a txt file and catching invalid numbers
Reading a line from a txt file and catching invalid numbers

Time:01-22

Say I have a .txt file which looks like this:

1234,3345
1246,3837
1283,5555
12P4,5730

I read each line as an int, but when I get to an invalid number like 12P4, how would I catch it without crashing the program and instead storing the invalid number in a list?

I am able to read it line by line, but I'm not sure how to catch the invalid number and continue processing more lines, catching more invalid numbers if present.

CodePudding user response:

I recommend that you read your file one line per loop iteration, using std::getline. In every loop iteration, you call std::string::find and std::string::substr to split the line into two strings, in which the first string contains everything before the , and the second string contains everything after the ,. You can then use the function std::stoi to attempt to convert the string to an integer. If this function fails, it will throw an exception. Also, using the middle function argument of std::stoi you can check whether the entire string was converted.

Here is an example program:

#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>

int main()
{
    std::ifstream input( "input.txt" );
    std::string line;

    while ( std::getline( input, line ) )
    {
        int num1, num2;

        //find delimiter
        std::string::size_type pos = line.find( ',' );
        if ( pos == std::string::npos )
        {
            std::cerr << "Warning: Skipping line due to splitting error!\n";
            continue;
        }

        //split line into two tokens
        std::string token1 = line.substr( 0, pos );
        std::string token2 = line.substr( pos   1, std::string::npos );

        //attempt to convert both tokens to integers
        try
        {
            size_t chars_matched_1, chars_matched_2;

            num1 = std::stoi( token1, &chars_matched_1, 10 );
            num2 = std::stoi( token2, &chars_matched_2, 10 );

            if (
                chars_matched_1 != token1.length()
                ||
                chars_matched_2 != token2.length()
            )
            {
                std::cerr << "Warning: Skipping line due to only partial conversion!\n";
                continue;
            }
        }
        catch ( const std::invalid_argument& )
        {
            std::cerr << "Warning: Skipping line due to conversion error!\n";
            continue;
        }
        catch ( const std::out_of_range& )
        {
            std::cerr << "Warning: Skipping line due to out of range error!\n";
            continue;
        }

        std::cout << "Found line with " << num1 << " and " << num2 << ".\n";
    }
}

For the input specified in the question, this program has the following output:

standard output (std::cout):

Found line with 1234 and 3345.
Found line with 1246 and 3837.
Found line with 1283 and 5555.

standard error (std::cerr):

Warning: Skipping line due to only partial conversion!

As you can see, it was detected that the string "12P4" could only be partially converted to an integer, so that line was skipped and a warning message was generated.

CodePudding user response:

Step 1: Read each line from the file into a string.
Step 2: Check the line consists of "number comma number".

std::string line;
while (std::getline(std::cin, line)) {
   // Read a line.
   std::istringstream   lineStream(line);
   int a, b;
   char x = 'X';
   char rem;

   if (lineStream >> a >> x >> b && x == ',' && !(lineStream >> rem)) {
       // Checks
       // 1: You can correctly read a Number char Number.
       // 2: The character you read is a comma
       // 3: There is no more text on the line that needs reading
       //    after the second number.
   }
   else {
       // There was a failure reading the numbers and/or comma
       // This will catch the 12P
}
  • Related