Nick
Nick

Reputation: 93

Using functions or methods in Java's String.replaceAll() regex

I am trying to convert an RPN-equation into a string that matches tigcc rules. There numbers must have the number of chars in front of them and a tag for positive or negative. For "2" it would be "1 2 POSINT_TAG"

My complete input to rpn converter is based on regexes, so I wanted to use them again and have a String.replaceAll() function like:

string.replaceAll("(\d+)","$1".length+" $1 POSINT_TAG");

But there it just prints: "2 number INT_TAG". I found some classes like com.stevesoft.pat (link).

Is there another way implemented in normal Sun Java to use (custom) functions in replace rules of regexes?

Upvotes: 6

Views: 4946

Answers (3)

Bob9630
Bob9630

Reputation: 953

Unfortunately what you are attempting here isn't going to work. Java uses applicative order evaluation meaning that the arguments are evaluated before the function is ever called. In your case you are getting the length of the two-character string "$1", not the number of digits that will be captured in group #1.

So when you use this line:

string.replaceAll("(\\d+)","$1".length+" $1 POSINT_TAG");   

What the function sees is:

string.replaceAll("(\\d+)","2 $1 POSINT_TAG");  

As for a solution to your problem, the answer posted by finnw will work.

Upvotes: 1

Fred Chin
Fred Chin

Reputation: 31

I have a idea about custom string replacement in Java. Not as easy as replacement function in JavaScript but it just works fine. Here is the code:


    package org.eve.util;

    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    public class StringUtils{
        public static String replaceWithFn(CharSequence input,String regexp,Method fn,int group){
            Matcher m=Pattern.compile(regexp).matcher(input);
            StringBuffer sb=new StringBuffer();
            try {
                Object obj=Modifier.toString(fn.getModifiers()).indexOf("static")>-1?
                        fn.getClass():fn.getDeclaringClass().newInstance();
                if(fn.getReturnType()!=String.class){
                    System.out.println("replacement function must return type \"String\".");
                }
                while(m.find()){
                    m.appendReplacement(sb, (String)fn.invoke(obj, m.group(group)));
                }
                m.appendTail(sb);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sb.toString();
        }
    }

 

    package org.eve.test;

import org.eve.util.StringUtils;

public class ReplaceTest {
    public static void main(String[] args) {
        try {
            StringBuffer input=new StringBuffer("\\u039D\\u03B9\\u03BA\\u03CC\\u03BB\\u03B1\\u03BF\\u03C2 Nicholas \\u5C3C\\u53E4\\u62C9\\u65AF");
            System.out.println("input="+input);
            String result=StringUtils.replaceWithFn(
                input,
                "\\\\u([0-9a-zA-Z]{4})",
                ReplaceTest.class.getMethod("hex2char",String.class),
                1
            );
            System.out.println("output="+result);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public String hex2char(String s){
        //TODO replaceholder
        return String.valueOf((char)Integer.parseInt(s,16));
    }
}

Just for fun.

Upvotes: 3

finnw
finnw

Reputation: 48619

No, at least not the same way you would do it in C# or Ruby.

The closest thing is to write a loop like this:

static Pattern pattern = Pattern.compile("\\d+");
String convert(String input) {
    StringBuffer output = new StringBuffer();
    Matcher matcher = pattern.matcher(input);
    while (matcher.find()) {
        String rep =
            String.format("%d %s POSINT_TAG",
                          matcher.group().length(),
                          matcher.group());
        matcher.appendReplacement(output, rep);
    }
    matcher.appendTail(output);
    return output.toString();
}

Upvotes: 13

Related Questions