0

I'm fairly certain this is asked & answered, but I cant find an (that) answer, so I'll ask:

I want to use javas regex to find and replace. There is no markup involved (no, "${ImMarkup!} in the source string) and the value I wish to replace is contextualized (as in, I cant write a simple replace A with B).

Examples make everything easier, here's some sample code. This is the source string:

! locator's position P1(p1x,p1y),P2(p2x,p2y)
R,1,0.001,0.001,0.001,0.001, , ,
RMORE, , , ,
RMORE   
RMORE, ,
ET,MPTEMP,,,,EX, x1=38000
x2 = 2345
MPTEMP,,,,,,,,  
MPTEMP,1,0  
MPDATA,EX,1,,38000*6894.75

my regex is

 +(?<variableName>\w+) *= *-?(?<variableValue>\d+\.?\d*)

(note the space before the first plus)

I'm looking to replace that "x1=38000" with something like "x1=100", and the "x2 = 2345" with "x2 = 200"

With the output

...
RMORE, ,
ET,MPTEMP,,,,EX, x1=100
x2 = 200
MPTEMP,,,,,,,,  
...

I've created a gist containing some semi-runnable code here (it uses some stuff from our commons code base, but its followable: https://gist.github.com/Groostav/acf5b584078813e7cbe6)

The code I've got is roughly

String regex = "+(?<variableName>\\w+) *= *-?(?<variableValue>\\d+\\.?\\d*)"
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(sourceText);

while(matcher.find()){

    String variableName = matcher.group("variableName");
    String existingValue = matcher.group("variableValue");

    int newValue;
    switch(variableName){
        case "x1": newValue = 100; break;
        case "x2": newValue = 200; break;
        default: throw new IllegalStateException();
    }

    matcher.appendReplacement(output, "" + newValue);

}

matcher.appendTail(output);

The regex itself works: it captures the values I need, and I can access them through matcher.group("variableName") and matcher.group("variableValue"), the issue I'm having is writing a new value back to 'variableValue', with the java regex API.

In the above example, matcher.group("variableValue") doesnt persist any state, so I cant seem to specify to the appendReplacement() method that I dont want to replace the whole line, but rather simply the second capture group.

Worth metnioning, x1 and x2 are not hard-fast runtime names, so I cant simply cheese it and write separate find and replace strings for x1 and x2. I need the runtime \w+ to find the variable name.

So I can run another regex against the result of the first, this time only capturing the value, but thats not pretty, and it would require me to probably fudge index values around with our StringBuilder/Buffer, rather than that nice index-free call to matcher.appendTail.

PS: the langauge you see above is called the "ANSYS parametric design language (APDL)", and I cant find a grammar for the thing. If any of you guys know where one is, I'd hugely appreciate it.

thanks for reading.

2 Answers 2

1

You can use this regex:

(\w+\s*)=(\s*\d+)

Working demo

Check the substitution section. You can use the same approach to replace the content you want as I did using capturing group index.

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

4 Comments

ahh, thanks but I dont actually have an issue with writing the regex itself, I actually have an issue with how I can consume the replacement mechanisms. Thanks anyways!
how about replacing the whole match but reconstruct it by prepending the first capture group and a =.
@Groostav thanks for +1. Btw, the idea for the answer was to show you the technique using capturing group to replace the content. You can try Markus comment. Check the link I provided and test this on Substitution section
So we did find a way to do it, I am using my below hack, but I cant thank you enough for pointing out this tool. Its explanations are good, its UI is simple, it seems to jive with the Java Regex interpreter. And its flat to boot. Good stuff.
0

My Hacky solution that seems to work is to manually traverse our parse tree, down the rhs, and replace the new value. This is annoying since it requires me to refactor my regex and do that manual work, but it does do the job, and I believe its reliable:

// semi-formally, APDL seems to define:
// AssignmentExpression     -> QualifiedIdentifier = Expression
// QualifiedIdentifier      -> SPACE+ Identifier SPACE*
// Expression               -> SPACE* Value  //Value is captured as "value"
// Identifier               -> [A-Za-z0-9]*  //Identifier is captured as "identifier"
// Value                    -> [0-9]* (DOT [0-9]*)?

private static final String rValue = "\\d+(\\.\\d*)?";
private static final String rIdentifier = "(?<identifier>\\w+)";
private static final String rQualifiedIdentifier = " +" + rIdentifier + " *";
private static final String rExpression = " *-?(?<value>" + rValue + ")";

private static final String rAssignmentExpression = rQualifiedIdentifier + "=" + rExpression;


@Test
public void when_scanning_using_our_regex(){
    Pattern assignmentPattern = Pattern.compile(rAssignmentExpression);
    Pattern rhsPattern =        Pattern.compile("=" + rExpression);
    Pattern valuePattern =      Pattern.compile(rValue);

    Matcher assignmentMatcher = assignmentPattern.matcher(sourceText);

    StringBuffer output = new StringBuffer();
    int newValue = 20;

    while(assignmentMatcher.find()){
        String assignment = assignmentMatcher.group();
        Matcher rhsMatcher = rhsPattern.matcher(assignment);
        assert rhsMatcher.find() : "couldn't find an RHS in an the assignment: '" + assignment + "'?";
        String oldRhs = rhsMatcher.group();
        Matcher valueMatcher = valuePattern.matcher(oldRhs);
        assert valueMatcher.find() : "couldn't find a value in an RHS: '" + oldRhs + "'?";

        String oldValue = valueMatcher.group();
        String newRhs = oldRhs.replace(oldValue, "" + newValue);
        String newAssignment = assignment.replace(oldRhs, newRhs);

        assignmentMatcher.appendReplacement(output, "" + newAssignment);
    }

    assignmentMatcher.appendTail(output);

    System.out.println(output.toString());

}

2 Comments

When you get a chance could you please clarify where the text and replacement is happening adding (put text here) put (replacement text here)
And could I use this to find and replace for wrong zip code with correct one

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.