Nilesh Gajare
Nilesh Gajare

Reputation: 6398

Extracting Formula from String

I have to extract all variables from Formula

Fiddle for below problem

eg. (FB+AB+ESI) / 12

Output {FB,AB,ESI}

Code written so far

var length = formula.Length;
            List<string> variables = new List<string>();
            List<char> operators = new List<char> { '+', '-', '*', '/', ')', '(', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
            int count = 0;
            string character = string.Empty;
            for (int i = 0; i < length; i++)
            {
                if (!operators.Contains(formula[i]))
                    character += formula[i];
                else
                {
                    if (!string.IsNullOrWhiteSpace(character))
                        variables.Add(character);
                    character = string.Empty;
                    count = i;
                }
            }
            if (!string.IsNullOrWhiteSpace(character))
                variables.Add(character);
            return variables;

Output of the Method is {FB,AB,ESI} which is correct

My problem is where Varaible contains numeric field i.e

eg. (FB1+AB1)/100

Expected Output : {FB1,AB1}

But My method return {FB,AB}

Upvotes: 0

Views: 1266

Answers (6)

Chris du Preez
Chris du Preez

Reputation: 539

Have changed your code to do what you asked, but not sure about the approach of the solution, seeing that bracket and operator precedence is not taken into consideration.

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        string formula = "AB1+FB+100";
        var length = formula.Length;
        List<string> variables = new List<string>();
        List<char> operators = new List<char>{'+', '-', '*', '/', ')', '('};
        List<char> numerals = new List<char>{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

        int count = 0;
        string character = string.Empty;
        char prev_char = '\0';

        for (int i = 0; i < length; i++)
        {
            bool is_operator = operators.Contains(formula[i]);
            bool is_numeral = numerals.Contains(formula[i]);
            bool is_variable = !(is_operator || is_numeral);
            bool was_variable = character.Contains(prev_char);

            if (is_variable || (was_variable && is_numeral) )
                character += formula[i];
            else
            {
                if (!string.IsNullOrWhiteSpace(character))
                    variables.Add(character);
                character = string.Empty;
                count = i;
            }

            prev_char = formula[i];
        }

        if (!string.IsNullOrWhiteSpace(character))
            variables.Add(character);

        foreach (var item in variables)
            Console.WriteLine(item);
        Console.WriteLine();
        Console.WriteLine();
    }
}

Maybe also consider something like Math-Expression-Evaluator (on nuget)

Upvotes: 2

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186708

If variable's names must start with

   letter A..Z, a..z

and if variable's names can contain

  letters     A..Z, a..z
  digits      0..1
  underscopes _

you can use regular expressions:

  String source = "(FB2+a_3B+EsI) / 12";

  String pattern = @"([A-Z]|[a-z])+([A-z]|[a-z]|\d|_)*";

  // output will be "{FB2,a_3B,EsI}"
  String output = "{" + String.Join(",", 
    Regex.Matches(source, pattern)
      .OfType<Match>()
      .Select(item => item.Value)) + "}";

In case you need a collection, say an array of variable's names, just modify the Linq:

  String names[] = Regex.Matches(source, pattern)
    .OfType<Match>()
    .Select(item => item.Value)
    .ToArray();

However, what is implemented is just a kind of naive tokenizer: you have to separate "variable names" found from function names, class names, check if they are commented out etc.

Upvotes: 2

Mark
Mark

Reputation: 8431

What you are trying to do is an interpreter.

I can't give you the whole code but what I can give you is a head start (it will require a lot of coding).

First, learn about reverse polish notation.

Second, you need to learn about stacks.

Third, you have to apply both to get what you want to interpret.

Upvotes: 0

Rufus L
Rufus L

Reputation: 37020

Without regex, you can split on the actual operators (not numbers), and then remove any items that begin with a number:

public static List<string> GetVariables(string formula)
{
    if (string.IsNullOrWhitespace(formula)) return new List<string>();

    var operators = new List<char> { '+', '-', '*', '/', '^', '%', '(', ')' };

    int temp;
    return formula
        .Split(operators.ToArray(), StringSplitOptions.RemoveEmptyEntries)
        .Where(operand => !int.TryParse(operand[0].ToString(), out temp))
        .ToList();
}

Upvotes: 1

Navik Hiralal
Navik Hiralal

Reputation: 787

Here is how you could do it with Regular Expressions.

        Regex regex = new Regex(@"([A-Z])\w+");

        List<string> matchedStrings = new List<string>();
        foreach (Match match in regex.Matches("(FB1+AB1)/100"))
        {
            matchedStrings.Add(match.Value);
        }

This will create a list of strings of all the matches.

Upvotes: 1

Rohit Prakash
Rohit Prakash

Reputation: 1972

You can do it this way, just optimize the code as you want.

       string ss = "(FB+AB+ESI) / 12";

        string[] spl =  ss.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
        string final = spl[0].Replace("(", "").Replace(")", "").Trim();
        string[] entries = final.Split(new char[] {'+'}, StringSplitOptions.RemoveEmptyEntries);
        StringBuilder sbFinal = new StringBuilder();
        sbFinal.Append("{");
        foreach(string en in entries)
        {
            sbFinal.Append(en + ",");
        }
        string finalString = sbFinal.ToString().TrimEnd(',');
        finalString += "}";

Upvotes: 0

Related Questions