0

I'm trying to use regex to get numbers and operators from a string containing an expression. It finds the numbers but i doesn't find the operators. After every match (number or operator) at the beginning of the string it truncates the expression in order to find the next one.

String expression = "23*12+11";
Pattern intPattern;
Pattern opPattern;
Matcher intMatch;
Matcher opMatch;

intPattern = Pattern.compile("^\\d+");
intMatch = intPattern.matcher(expression);
opPattern = Pattern.compile("^[-+*/()]+");
opMatch = opPattern.matcher(expression);


while ( ! expression.isEmpty()) {
    System.out.println("New expression: " + expression);
        if (intMatch.find()) {
            String inputInt = intMatch.group();
            System.out.println(inputInt);
            System.out.println("Found at index: " + intMatch.start());
            expression = expression.substring(intMatch.end());
            intMatch = intPattern.matcher(expression);
            System.out.println("Truncated expression: " + expression);
        } else if (opMatch.find()) {
            String nextOp = opMatch.group();
            System.out.println(nextOp);
            System.out.println("Found at index: " + opMatch.start());
            System.out.println("End index: " + opMatch.end());
            expression = expression.substring(opMatch.end());
            opMatch = opPattern.matcher(expression);
            System.out.println("Truncated expression: " + expression);
         } else {
        System.out.println("Last item: " + expression);
        break;
         }
    }

The output is

New expression: 23*12+11
23
Found at index: 0
Truncated expression: *12+11
New expression: *12+11
Last item: *12+11   

As far as I have been able to investigate there is no need to escape the special characters *, + since they are inside a character class. What's the problem here?

2
  • You're using the wrong tool for the job. You need to write a separate scanner and parser. Commented Apr 5, 2014 at 23:19
  • Yes, I read about that too. But I don't really know how to do that. Regex I know from python and sed. Anyway, what's the problem with regex since it works? Commented Apr 5, 2014 at 23:33

3 Answers 3

3

First, your debugging output is confusing, because it's exactly the same in both branches. Add something to distinguish them, such as an a and b prefix:

System.out.println("a.Found at index: " + intMatch.start());

Your problem is that you're not resetting both matchers to the updated string. At the end of both branches in your if-else (or just once, after the entire if-else block), you need to do this:

intMatch = intPattern.matcher(expression);
opMatch = opPattern.matcher(expression);

One last thing: Since you're creating a new matcher over and over again via Pattern.matcher(s), you might want to consider creating the matcher only once, with a dummy-string, at the top of your code

//"": Unused string so matcher object can be reused
intMatch = Pattern.compile(...).matcher("");

and then resetting it in each loop iteration

intMatch.reset(expression);

You can implement the reusable Matchers like this:

//"": Unused to-search strings, so the matcher objects can be reused.
Matcher intMatch = Pattern.compile("^\\d+").matcher("");
Matcher opMatch = Pattern.compile("^[-+*/()]+").matcher("");

String expression = "23*12+11";

while ( ! expression.isEmpty()) {
   System.out.println("New expression: " + expression);

   intMatch.reset(expression);
   opMatch.reset(expression);

   if(intMatch.find()) {
      ...

The

Pattern *Pattern = ...

lines can be removed from the top, and the

*Match = *Pattern.matcher(expression)

lines can be removed from both if-else branches.

Sign up to request clarification or add additional context in comments.

2 Comments

That works fine. But I didn't get the dummy-string part (where at the top? Inside the while?) I just kicket out the opMatch = opPattern.matcher(expression); and replaced it with the two resets and it works fine.
Glad it helped. I'm about to update my answer with some more information about dummy-string/reusing the matcher.
1

Your main problem is that when you found int you or operator you are reassigning only intMatch or opMatch. So if you find int operator is still try to find match on old version of expression. So you need to place this lines in both your positive cases

intMatch = intPattern.matcher(expression);
opMatch = opPattern.matcher(expression);

But maybe instead of your approach with two Patterns and recreating expression just use one regex which will find ints or operators and place them in different group categories? I mean something like

String expression = "23*12+11";
Pattern p = Pattern.compile("(\\d+)|([-+*/()]+)");
Matcher m = p.matcher(expression);
while (m.find()){
    if (m.group(1)==null){//group 1 is null so match must come from group 2
        System.out.println("opperator found: "+m.group(2));
    }else{
        System.out.println("integer found: "+m.group(1));
    }
}

Also if you don't need to separately handle integers and operators you can just split on places before and after operators using look-around mechanisms

String expression = "23*12+11";
for (String s : expression.split("(?<=[-+*/()])|(?=[-+*/()])"))
    System.out.println(s);

Output:

23
*
12
+
11

Comments

0

Try this one

Note:You have missed modulus % operator

    String expression = "2/3*1%(2+11)";

    Pattern pt = Pattern.compile("[-+*/()%]");
    Matcher mt = pt.matcher(expression);
    int lastStart = 0;
    while (mt.find()) {
        if (lastStart != mt.start()) {
            System.out.println("number:" + expression.substring(lastStart, mt.start()));
        }
        lastStart = mt.start() + 1;
        System.out.println("operator:" + mt.group());
    }

    if (lastStart != expression.length()) {
        System.out.println("number:" + expression.substring(lastStart));
    }

output

number:2
operator:/
number:3
operator:*
number:1
operator:%
operator:(
number:2
operator:+
number:11
operator:)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.