Click here to Skip to main content
15,910,981 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to figure this out but I believe I have went about it with the wrong idea of how to get the right result.

Initially I planned on trying to do something like this:

C++
std::string patterns::xPlode(std::string sOrig, int endsOrig){
	std::string holder = "";
	std::string finishedXplode = "";
	int origEnds = endsOrig;
	std::string Orig = sOrig;
	std::string holder2 = "";
	int paren1num = 0;
	int paren2num = 0;
	int paren3num = 0;
	std::string paren1 = "";
	bool paren1closed = false;
	std::string paren2 = "";
	bool paren2closed = false;
	std::string paren3 = "";
	bool paren3closed = false;
	static std::regex reg1("[0-9]+");
	std::string cOrig = Orig.c_str();
	int repeatsComplete = 0;
	int numSci = 0;

	for (int i = 0; i < ((origEnds / cOrig.size()) + 1); i++){
		holder += Orig;
	}

	for (int i = 0; i < holder.length(); ++i){
		if (isdigit(holder.at(i))){
			if (!paren1closed){
				if (paren1num > 0){
					if ((0 <= holder.at(i)) && (holder.at(i) >= ((_MAX_INT_DIG - 9) / 10))) {
						paren1num = (paren1num * 10) + holder.at(i);
						break;
					}
					else{
						puts("ERROR _ OVERFLOW!!! err:1001");
						break;
					}
				}
				else{
					paren1num = (int)holder.at(i);
					break;
					}
				}
			}
			else if (!paren2closed){
				if (paren2num > 0){
					if ((0 <= holder.at(i)) && (holder.at(i) >= ((_MAX_INT_DIG - 9) / 10))) {
						paren2num = (paren2num * 10) + holder.at(i);
						break;
					}
					else{
						puts("ERROR _ OVERFLOW!!! err:1002");
						break;
					}
				}
				else{
					paren2num = (int)holder.at(i);
					break;
				}
			}
			else if (!paren3closed){
				if (paren3num > 0){
					if ((0 <= holder.at(i)) && (holder.at(i) >= ((_MAX_INT_DIG - 9) / 10))) {
						paren3num = (paren3num * 10) + holder.at(i);
						break;
					}
					else{
						puts("ERROR _ OVERFLOW!!! err:1003");
						break;
					}
				}
				else{
					paren3num = (int)holder.at(i);
					break;
				}
		}
		else if (holder.at(i) == *"("){//if open parens
			if (!paren1closed){
				paren1closed = !paren1closed;

				break;
			}
			else if (!paren2closed){
				paren2closed = !paren2closed;
				break;
			}
			else if (!paren3closed){
				paren3closed = !paren3closed;
				break;
			}
		} 
		else if (holder.at(i) == *")"){ //if closed paren
			if (paren3closed){
				paren3closed = !paren3closed;

				break;
			}
			else if (paren2closed){
				paren2closed = !paren2closed;
				break;
			}
			else if (paren1closed){
				paren1closed = !paren1closed;
				break;
			}
		}

		// end WIP

	}


	cOrig = holder.c_str();
	for (int i = 0; i < origEnds; ++i){
		finishedXplode = finishedXplode + cOrig[i];
	}

	finishedPat = finishedXplode;
	return finishedXplode;
}


The code here is unfinished because I had second thoughts about my logic. The idea was to walk through each character and decide if it was a number, or open or close parenthesis and save that information into a string, using the number to repeat what is in the parenthesis. and alowing for iteration in the event that another statement is inside the parenthesis.

For example :
2(ab)16(cd)3(a4(bc)d)

would equate to :
ABABCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDABCBCBCBCDABCBCBCBCDABCBCBCBCD

I know the code is very sloppy, and I am open to every suggestion you guys can give me to help get better at C++.
Posted

I'd write a recursive descent parser instead of something based on regular expressions. Admittedly, regex style syntax is a handy way to describe parts of the problem.

Grammar rules ...

number = [0-9]+
literal = [A-Z]+
expression = [ literal | number '(' expression ')' ]+

C++
#include <string>

// I'll leave the scanner class to your imagination.

class Scanner
{
   // TODO
public:
    Scanner(const char *text);

    // Each of these functions returns true 
    // if a pattern is found. Matched input is 
    // "consumed" (index or cursor into the buffer 
    // advances). If the function returns false, 
    // nothing happens.

    // look for [0-9]+
    bool parseNumber(int &number);

    // look for [A-Z]+
    bool parseLiteral(std::string &literal);

    // look for single character eg. '(' or ')'
    bool parseMatch(char text);

    // returns true of no more text to consume.
    bool empty() const;
};


C++
#include <string>
#include <stdio.h>
#include "Scanner.h"

// recursive descent parser
static bool parseExpression(Scanner &buffer, std::string &output)
{
    int number = 0;
    while ( !buffer.empty() )
    {
        std::string nested;
        if ( buffer.parseLiteral(nested) )
        {
           output.push_back(nested);
        }
        else if ( buffer.parseNumber(number)
        {
            if ( buffer.parseMatch('(') && 
                parseExpression(buffer, nested) && // recursive
                buffer.parseMatch(')')
            {
                while (number > 0)
                {
                    output.push_back(nested);
                    number--;
                }
            }
            else
            {
                return false;
            }
        }
        else 
            return false;
    }
    return true;
}

// unit test
int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; i++)
    {
        Scanner buffer(argv[i]);
        std::string result;
        if ( parseExpression(buffer, result) )
            printf("Result: %s\n", result.c_str());
        else
            printf("Error parsing %s\n". argv[i]);
    }
    return 0;
}
 
Share this answer
 
v3
I think the key here is recursion.
Addressing the nested part of your grammar (handling repetition, and minor details like uppercase, is left has an exercise ;-) ),
we can write:
expr :=   num '(' left expr right ')' 
        | empty;

where num is a sequence of (one or more) digits while left and right are sequences of (zero or more) letters.

We may write something like the following code:

C++
// expr = num '(' left expr right ')' | empty

#include <iostream>
using namespace std;

struct Exc
{
  string msg;
  size_t pos;
};


bool get_num( const string & input, size_t & pos, size_t & num )
{
  num = 0;
  bool result = false;
  while ( pos < input.length() && input[pos] >= '0' && input[pos] <= '9')
  {
    result = true;
    num = num * 10 + (input[pos] - '0');
    ++pos;
  }
  return result;
}

bool get_lbrace( const string & input, size_t & pos )
{
  if ( pos >= input.length() || input[pos] != '(') return false;
  ++pos;
  return true;
}

bool get_rbrace( const string & input, size_t & pos )
{
  if ( pos >= input.length() || input[pos] != ')') return false;
  ++pos;
  return true;
}

bool get_alpha( const string & input, size_t & pos, string & alpha)
{
  bool result = false;
  alpha = "";
  while ( pos < input.length() && input[pos] >='a' && input[pos] <='z')
  {
    result = true;
    alpha += input[pos];
    ++pos;
  }
  return result;
}

void expr( string & input, size_t & pos)
{
  size_t num;
  string left = "";
  string right = "";
  if ( ! get_num( input, pos, num )) return;
  size_t bkpos = pos;
  for (size_t n=0; n<num; ++n)
  {
    pos = bkpos;
    if ( ! get_lbrace( input, pos ))
    {
      Exc exc = {"missing left brace", pos};
      throw exc;
    }
    get_alpha( input, pos, left );
    cout << left;
    expr(input, pos);
    get_alpha(input, pos, right);
    cout << right;
    if ( ! get_rbrace( input, pos))
    {
      Exc exc = {"missing right brace", pos};
      throw exc;
    }
  }
}


int main()
{
  string myexpr = "12(a3(b2(ywz))c)";
  size_t pos = 0;
  try
  {
    expr( myexpr, pos);
  }
  catch( Exc exc )
  {
    cerr << endl << exc.msg << " at " << exc.pos <<  endl;
  }
  cout << endl;
}
 
Share this answer
 
v2
Comments
stvn1337 23-Mar-15 23:07pm    
This is exactly what my idea was. I am actually in college, and actively learning c++. This was not homework or a project so don't worry there. I was wanting to learn more about recursion, and had this idea. Every time I tried to figure out the logic required to get the result I wanted I got stuck. I have studied your code and I see exactly what you did to make it happen. Thank you for taking the time to help teach me.
CPallini 24-Mar-15 2:55am    
You are welcome.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900