Home > Java > Reducing the Necronomicon to numbers….

Reducing the Necronomicon to numbers….

Abdul Alhazred, in his crazed and infinite wisdom, besides being the author of the Necronomicon was also something of a part time numerologist. Between inscribing in blood (derived from virgins, a scarce commodity in the circles in which Abdul moved) the memorial pages which have driven many beyond the brink of sanity, he spent much time in contemplating how one might reductively turn language into numbers. One method which he overlooked was that proposed by Mr Donovan K. Loucks. It appeared as a comment to an earlier post on “Counting vowels… the faster AND dynamically reusable way…” and in essence what we need to do here is take a given String, remove non-vowels, i.e. consonants, punctuation and whitespace, replace the vowels with “+1” and suffix a “0” to the end so that the final number to be added will be a ten.

The replacement is easy enough using the locateStringContents method set out earlier, which we’ll bolt into a putative new class called LovecraftEvaluator, along with the boringly necessary toIntArray method which appears more times on this blog than Cthulhu has yawned in the sleeping millenia. We don’t actually need to replace anything at all, given that we are just interested in the vowels, so we’ll just create a new StringBuffer and for each vowel append a “+1” and StringBuffer.join a “0” once this is complete. Then we have to calculate the sum of these numbers….


String test = "The Necronomicon does not make for light reading. At all.";
LovecraftEvaluator le = new LovecraftEvaluator();
String vowels = "aeiouAEIOU";
int[] positions = le.locateStringContents(new StringBuffer(test), new StringBuffer(vowels));

int ctr = 0;
StringBuffer sOut = new StringBuffer();
for (int i = 0; i < positions.length; i++)
{
sOut.append("+1");
}
sOut.append(0);

If we print the contents of sOut we’ll get this:

+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+10

Now we’re onto phase 2, evaluating the String mathematically. Java still doesn’t have closures or lambdas, even though they’ve been on the request list since the early middle ages. Apparently they’re proposed for JDK 7 but I won’t be holding my breath; something we’ve taken for granted since year 1 in Ruby is still unimplemented in Java and likely to remain so in the near future.

Aside from the obvious occult usages of being able to reduce Strings to their numerical values, there is a serious method behind this which will allow you to calculate a mathematically expressed String effortlessly. I won’t bore you overmuch with details but it’s easy enough to do by casting your Stringbuffer to a char[] array and then walking the array as necessary and calculating the outcome as you go along. This method with its helpers should allow you to process most mathematically expressed Strings. Obviously if you’re working with floats etc, you would have to overload and extend the metaphor, but generally what’s needed is not much beyond the skeletal framework we have here (you’ll need to handle decimal points being the main difference). Typically your method for the LovecraftEvaluator class should look something like this


public int sbMathEvaluator(StringBuffer sb)
    {
    int result = 0;
    char operator = ' ';
    String tmp = "";

    char[] aEval = sb.toString().toCharArray();
    int last = aEval.length;

    for (int i = 0; i < aEval.length; i++) // each character we have....
    {
    if(!isInt(aEval[i])) // if it's not an int we'll change the value of the operator and go back to the top of the loop
    {
    operator = aEval[i];
    tmp = ""; // reset tmp
    continue;
    }

// if we got here it's an int (at least 1) & there may be more so don't calc just yet....
    tmp += Character.toString(aEval[i]);

    if(i + 1 == last){ // we really don't want an array exception here so this is the final calc on the last number
    result = calc(result,operator,toInt(tmp))    ;
        break;}
    if(!isInt(aEval[i + 1])) // if the next char's an operator, recalculate
    {
    result = calc(result,operator,toInt(tmp))    ;
    }

    }

    return result;
    }

The helpers you will need are as follows. Firstly the calc method which takes the running total, the operation to perform, and the value to apply to it as arguments. Although we’re just doing addition it doesn’t hurt to make it relatively generic. You could add other operators etc, but let’s keep it relatively simple for illustrative purposes…


public int calc(int result, char operator, int val)
    {
    if (operator == '+')
    {return result + val;}
    if (operator == '-')
    {return result - val;}
    if (operator == '*')
    {return result * val;}
    if (operator == '/')
    {return result / val;}
// no op possible? just throw back the result unmutated
    return result;
    }

And we’ll need a few little syntax helpers. Feel free to rip these and rep them as necessary, they’re for convenience mainly.


   public int toInt(String tmp)
    {
    return Integer.parseInt(tmp);
    }

    public int toInt(char c)
    {
    return Character.getNumericValue(c);
    }

    public boolean isInt(char c)
    {
    int i = Character.getNumericValue(c);
    if (i >= 0){        return true;}
    return false;
    }

public int[] toIntArray(List<Integer> integerList) {
int[] intArray = new int[integerList.size()];
for (int i = 0; i < integerList.size(); i++) {
intArray[i] = integerList.get(i);
}
return intArray;
}

As an afterthought, if you're going to reduce something of the length of teh Necronomicon to its numerical value, you'd probably be advised to add the earlier countStringContents method to the class also and set the capacity of your target replacement StringBuffer to twice that number + a few e.g.

String test = "The complete and unexpurgated contents of the Necronomicon.... etc";
LovecraftEvaluator le = new LovecraftEvaluator();
String vowels = "aeiouAEIOU";
int[] positions = le.locateStringContents(new StringBuffer(test), new StringBuffer(vowels));
int numVowels = le.countStringContents(test,vowels);
numvowels = (numVowels * 2) + 50;

int ctr = 0;
StringBuffer sOut = new StringBuffer();
sOut.ensureCapacity(numVowels);
for (int i = 0; i < positions.length; i++)
{
sOut.append("+1");
}
sOut.append(0);

 

Advertisements
  1. February 11, 2010 at 3:45 am

    I made an error in my original comment. Just to clarify, my intent was to end up with a string that looked something like this: “1+1+1+1+1+1+0”. The “0” at the end was to eliminate the need to truncate the trailing plus sign. As such, each vowel should’ve been replaced with “1+” rather than “+1” (though the “0” could then have been added at the beginning). In short, I didn’t intend to add “10” at the end, but just to replace all vowels with “1+”.

    Donovan K. Loucks
    Webmaster, The H. P. Lovecraft Archive
    http://www.hplovecraft.com/

    P.S. A Google Alert on “Lovecraft” is what directed me to your blog. I happen to be a web developer specializing in SQL Server applications using VBScript (though, on a whim, I did use Javascript for one site I developed).

  2. syzygy
    February 11, 2010 at 5:04 am

    Donovan, serendipity strikes again – I managed to get a Java String math calculator out of that 🙂 Just don’t do the postpend of the 0 or even simpler use the earlier vowel count method (the results are 100% statistically likely to be equivalent :)). BTW I have always been a great admirer of http://www.hplovecraft.com, it’s the way web design ought to be done, lean, clean, and unfussy.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: