简体   繁体   中英

Java Regex finding operators

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?

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 reset ting 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.

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

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:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM