-3

I'm trying to parse out mathematical equation from given char array, for example char equation[255] = "4+4"; and I want to copy first number to long number1, operator to char oper and second number to long number2.

I've tried sscanf(equation, "%d%c%d", &number1, &oper, &number2); but it just gets first number and fails to extract operator and second number.

Tried this method:

while (isdigit(equation[k]))
    {
        k++;
    }                   
oper = equation[k];

and still it doesn't get the operator. Is there more simple way to parse out equation in c++?

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 3
    "It doesn't get the operator." A small, self-contained, compilable example would be nice so we could see exactly what you are seeing. Actually, *not* providing such an example is one of the reasons to "vote for close".... – DevSolar Mar 16 '16 at 08:11
  • Are you sure you entered `equation = "4+4"` and not `"4 + 4"` (note the additional spaces)? – CompuChip Mar 16 '16 at 08:22
  • 2
    I also took the liberty of changing the C++ tag into a C tag, as this is C. If you're doing C++, please use `` instead of `char[]`, and C++ iostreams instead of `*scanf()`. – DevSolar Mar 16 '16 at 08:24

2 Answers2

7

Turning this into an MCVE...

#include <stdio.h>

int main()
{
    char * equation = "4+4";
    long number1, number2;
    char oper;
    int rc = sscanf( equation, "%d%c%d", &number1, &oper, &number2 );
    printf( "%d\n", rc );
    if ( rc == 3 )
    {
        printf( "%d - %c - %d\n", number1, oper, number2 );
    }
    return 0;
}

...gives...

3
4 - + - 4

Works as intended. Voting to close the question, please read the link I gave at the beginning of my answer.

Also:

  • How to read / parse input in C?, sections:
    • Do not use *scanf() for potentially malformed input
    • When *scanf() does not work as expected (for if your input string contains spaces)

If you actually want to use C++ (as your original tag indicated), there's Boost.Spirit for your parsing needs.

Community
  • 1
  • 1
DevSolar
  • 67,862
  • 21
  • 134
  • 209
3

If you want to write a simple lexer in C++, here is one I adapted math-expr-lexer.cpp (Author: Dmitry Soshnikov), to make it work on MS Windows OS.

#include <iostream>
#include <vector>
#include <ctype.h>
#include <cstring>

#define NL std::endl   

class Lexer {

private:
    char* m_source;
    int   m_sourceLength;
    int   m_cursor;
    char  m_currentChar;

    void  readNextChar();
    void  skipWhiteSpaces();
    char* readNumber();
    char* readSymbol();

public:
    Lexer(char* source);

    bool isEOF();
    char* readNextToken();
    static std::vector<char*> tokenize(char*);
};

// ---------------------------------
// Lexer implementation.
// ---------------------------------

Lexer::Lexer(char* source) {
    m_source = source;
    m_sourceLength = strlen(source);
    m_cursor = 0;

    readNextChar();
}

bool Lexer::isEOF() {
    return m_cursor > m_sourceLength;
}

/**
 * Reads next char advancing cursor.
 */
void Lexer::readNextChar() {
    skipWhiteSpaces();

    if (isEOF()) {
        m_currentChar = '\0';
        return;
    }

    m_currentChar = m_source[m_cursor++];
}

/**
 * Reads next token: a number or a symbol.
 */
char* Lexer::readNextToken() {
    if (isdigit(m_currentChar))
        return readNumber();

    return readSymbol();
}

/**
 * Reds a number containing digits.
 */
char* Lexer::readNumber() {
    char* number = new char[20];
    int i = 0;
    while (isdigit(m_currentChar)) {
        number[i++] = m_currentChar;
        readNextChar();
    }
    number[i] = '\0';
    return number;
}

/**
 * Reads a symbol (operator or grouping).
 */
char* Lexer::readSymbol() {
    char* symbol = new char[2];
    symbol[0] = m_currentChar;
    symbol[1] = '\0';
    readNextChar();
    return symbol;
}

void Lexer::skipWhiteSpaces() {
    while (isspace(m_source[m_cursor]))
        m_cursor++;
}

/**
* Tokenizes a source expression, returns
* a vector with the tokens.
*/
std::vector<char*> Lexer::tokenize(char* source) {
    std::vector<char*> tokens;
    Lexer lexer(source);
    do {
        tokens.push_back(lexer.readNextToken());
    } while (!lexer.isEOF());
    return tokens;
}

void printTokens(std::vector<char*> tokens) {
    std::cout << "Tokens: [";
    unsigned int size = tokens.size();
    for (unsigned int k = 0; k < size; k++) {
        std::cout << '"' << tokens[k] << '"';
        if (k < size - 1) std::cout << ", ";
    }
    std::cout << "]" << NL << NL;
}

int main()
{ 
    char* expression = new char[100];
    std::cout << "Enter expression: ";
    std::cin.getline(expression, 100);
    printTokens(Lexer::tokenize(expression));
    return 0;
}
vcp
  • 962
  • 7
  • 15