Hazem Elraffiee
Hazem Elraffiee

Reputation: 453

How to do calculations on regex parts in a replaceAll before replacing?

I have a string like: "2E6 3.34e-5 3 4.6" and I want to use replaceAll to replace tokens like:

"((\\-)?[0-9]+(\\.([0-9])+)?)(E|e)((\\-)?[0-9]+(\\.([0-9])+)?)"

(i.e. two numbers with e or E between them) into the equivalent normal number format (i.e. replace "2E6" with "2000000" and "3.34e-5" with "0.0000334")

I wrote:

value.replaceAll("((\\-)?[0-9]+(\\.([0-9])+)?)(E|e)((\\-)?[0-9]+(\\.([0-9])+)?)", "($1)*10^($6)");

but I would like to actually multiply the 1st argument by 10 to the power of the 2nd argument, not just writing it that way .. Any ideas?

UPDATE

I did the following based on your suggesions:

Pattern p = Pattern.compile("((\\-)?[0-9]+(\\.([0-9])+)?)(E|e)((\\-)?[0-9]+(\\.([0-9])+)?)");
Matcher m = p.matcher("2E6 3.34e-5 3 4.6");
StringBuffer sb = new StringBuffer();
while (m.find()) {
    m.appendReplacement(sb, "WHAT HERE??"); // What HERE ??
}
m.appendTail(sb);
System.out.println(sb.toString());

UPDATE

Finally, this is what I reached:

// 32 #'s because this is the highest precision I need in my application
private static NumberFormat formatter = new DecimalFormat("#.################################");

private static String fix(String values) {
    String[] values_array = values.split(" ");
    StringBuilder result = new StringBuilder();
    for(String value:values_array){
        try{
            result.append(formatter.format(new Double(value))).append(" ");
        }catch(NumberFormatException e){ //If not a valid double, copy it as is
            result.append(value).append(" ");
        }
    }
    return result.toString().substring(0, result.toString().length()-1);
}

Upvotes: 0

Views: 361

Answers (4)

Ian Roberts
Ian Roberts

Reputation: 122414

If you want to do anything more complicated than copying groups verbatim from the match to the replacement then you'll have to do it longhand using the find() and appendReplacement/appendTail methods of Matcher. There's a good example in the javadoc for appendReplacement.

Inside the loop you can use m.group() to access the matched string, and m.group(n) to access the n'th parenthesis group, so you could create a suitable NumberFormat for the output format you need and then do something like

double val = Double.parseDouble(m.group());
m.appendReplacement(nf.format(val));

Or using String.format

m.appendReplacement(String.format("%f", val));

(or use BigDecimal if you can't be sure your values will all be representable as double).

Upvotes: 0

mtk
mtk

Reputation: 13717

If you need to convert scientific number notation into normal formal you can use DecimalFormat

public static void main(String[] args) {
    NumberFormat formatter = new DecimalFormat();

    double num1 = 2E6;
    formatter = new DecimalFormat("##########");
    System.out.println(formatter.format(num1)); 

    double num2 = 3.3e-5;
    formatter = new DecimalFormat("#.##########");
    System.out.println(formatter.format(num2));
}

Just add the logic to split the intial string over spaces and apply the above logic.

You can check more about the symbols like #(in this case) at the javadoc for DecimalFormat.

Symbol Location     Localized?  Meaning   
------------------------------------------------------------
#      Number       Yes         Digit, zero shows as absent 

Upvotes: 1

Esailija
Esailija

Reputation: 140236

    StringBuffer buffer = new StringBuffer();

    Pattern regex = Pattern.compile("((\\-)?[0-9]+(\\.([0-9])+)?)(E|e)((\\-)?[0-9]+(\\.([0-9])+)?)");
    Matcher matcher = regex.matcher( "2E6 3.34e-5 3 4.6");
    while (matcher.find()) {

      String a = matcher.group(1); //The $1
      String b = matcher.group(6); //The $6
      String repl = null;
      if( a != null && b != null ) { //Check if both exist for this match
                      //Parse, do calculations and convert to string again
          repl = BigDecimal.valueOf( Double.parseDouble( a ) * Math.pow( 10, Double.parseDouble( b ) )).toString();
      }
      else {
          repl = matcher.group(0); //Else return unaffected
      }
      matcher.appendReplacement(buffer, repl);
    }
    matcher.appendTail(buffer);

    System.out.println( buffer.toString());
     //"2000000.0 0.0000334 3 4.6"

Upvotes: 2

ddmps
ddmps

Reputation: 4390

I don't think you'll be able to do that with replaceAll method. You seem to know regex so I'll only point you in the right direction. Try the Pattern and Matcher class. With this, you can compile a regex pattern and find groups, and for example multiply the first group with 10 to the power of the group after e.

Upvotes: 0

Related Questions