2

Suppose I have an enum class like the one from Oracle’s example:

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    //...

I need to multiply all of the numbers in the class by 0.33. I don’t want to code the calculation in the enum, but to change the text itself. What’s the fastest way to automate this in Vim / IDEA / any other tool?

Ben Klein
  • 1,719
  • 3
  • 18
  • 41
Dave's tux
  • 123
  • 2

3 Answers3

1

Using vim, I would attempt the following:

:% s /\(\d\+\.\d\+\)/\=(submatch(1) * 0.33)/gc 

This will match each number (\d+.\d+) in the entire file (%) and substitute (s) it with the results (\=) of multiplying (*) the matched number (submatch(1)) by 0.33.

kjelderg
  • 392
  • 3
  • 5
  • I actually don't need exponents, but I do need to handle whole number (without .) too. I guess with some modifications this can be the solution for my need. – Dave's tux Oct 14 '13 at 20:32
  • It's true, you caught me there. It does not _actually_ handle the exponent correctly which could result in a denormalized representation of the number. – kjelderg Oct 14 '13 at 20:54
  • Someone answered and deleted the following line: :%s/[0-9.]\+/\=submatch(0) * 0.33/g which detect integers too, but have alot of false positives – Dave's tux Oct 14 '13 at 21:08
  • @Dave'stux I was the one who deleted that. Did that help you? I can read add if it did, but it also did not work for exponents. – fvrghl Oct 14 '13 at 21:53
  • @fvrghl I don't need the exponents, I shouldn't have used that example. however your solution changed every occurrence of a '.' in the file. – Dave's tux Oct 14 '13 at 21:58
  • So you want 2.4e6 to become 1.6e1.98? If so, this should work: :% s /\(\d\+\(\.\d\+\)\?\)/\=(submatch(1) * 0.33)/gc This makes the decimal portion optional – kjelderg Oct 14 '13 at 22:01
  • @kjelderg I get: E486: Pattern not found: (\d\+(\.\d\+)\?) – Dave's tux Oct 14 '13 at 22:15
  • My apologies, a couple slashes got lost somewhere: That should have been :% s /\\(\d\+\\(\.\d\+\\)\?\\)/\=(submatch(1) * 0.33)/gc – kjelderg Oct 14 '13 at 23:04
1

If you go the macro route, this is one way to replace a visually selected number with itself multiplied by 0.33:

c
<C-r>=
<C-r>"
*0.33
<CR>
romainl
  • 186,200
  • 21
  • 280
  • 313
  • This is working. but because the class is very long this approach will require a lot of labour. Ultimately the macro will include a search and visual select for the next number. – Dave's tux Oct 14 '13 at 21:06
0

I switched to python for this one. Consider the following script:

#!/usr/bin/env python
import re

numeric_const_pattern = r"""
[-+]? # optional sign
(?:
    (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
    |
    (?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)

with open('code.txt') as fd:
    for line in fd:
        num = rx.findall(line)
        for n in num:
            line = line.replace(n, str(float(n)*.33))
        print line.rstrip()

Output:

$ ./num.py 
public enum Planet {
    MERCURY (1.08999e+23, 805101.0),
    VENUS   (1.60677e+24, 1997094.0),
    EARTH   (1.97208e+24, 2104786.2),
    MARS    (2.11893e+23, 1121076.0),
    JUPITER (6.27e+26,   23592360.0),
    SATURN  (1.87704e+26, 19888440.0),
    URANUS  (2.86638e+25, 8434470.0),
    NEPTUNE (3.3792e+25, 8166180.0);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m0.99 kg-0.33 s-0.66)
    public static final double G = 2.20209e-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }

Not perfect, since all numbers basically get multiplied with 0.33. kg-1 gets transformed into kg-0.33 etc. But it's a start. Next step is to ignore comments and reduce false positives...

Fredrik Pihl
  • 44,604
  • 7
  • 83
  • 130