Page 1 of 1

Gematria Converter

Posted: Sun May 25, 2008 7:28 am
by veleshanas
Hello forum,

I have just finished writing a PHP/HTML page that converts Arabic numbers into Hebrew numerals (each of 22 Hebrew alphabets having a numerical value) and vice versa. I present the entire PHP file below.

The program works in the following steps:
1. Input through Textbox "in" is matched against two regex formula (thanks, GeertDD).
2. If the input is an integer from 1 to 999, it is processed by the num2heb logic.
3. If the input solely consists of Hebrew characters, it is processed by the heb2num logic.
4. The num2heb logic converts a number into a Hebrew numeral, or a string of Hebrew letters, the sum of whose values equalling to the input.
5. The heb2num logic calculates the numerical value of a Hebrew string.
6. The results are printed out.

I am wondering if there is any way to improve num2heb. I think I am using too many interceding variables to get the final result. Does any one know a simpler and more elegant way to do what I did?

a. The first bunch of if-clauses determines $_900, the Hebrew numeral representation of the hundreds of the input.
b. The tens and units part is extracted from the original input ($_in099) and thrown into the second bunch of if-clauses, which returns the Hebrew numeral of the tens ($_090).
c. The units part ($_in009) of the input is thrown into the third bunch of if-clauses and converted into the Hebrew numeral of the units ($_009).
d. The fourth if-bunch creates the Hebrew representation for the tens and units ($_099) out of concatenation of $_090 and $_009. Exceptional creation of $_099 for 15 and 16 is written in the same section.
e. The results of Processes a. and d. are concatenated as the final outcome; $_999.


:wink: veleshanas

Code: Select all

<HTML>
 
<HEAD>
<TITLE>GemConverter<TITLE/>
<META docOwner = "veleshanas" DATE = "2008-04-08">
<META REVISION = "added hb2num logic" DATE = "2008-05-25">
<META writtenFor ="PHP Version 5.2.4-2ubuntu5">
<META HTTP-EQUIV = "Content-Type" CONTENT = "text/html; charset=utf-8">
 
</HEAD>
 
<BODY>
 
GemConverter returns:<BR />
&nbsp;&nbsp;&nbsp;a. Hebrew numerals for integers from 1 to 999<BR />
&nbsp;&nbsp;&nbsp;b. Numerical values for any length of Hebrew strings
<BR /><BR />
 
<FORM ACTION = "GemConverter.php" METHOD = "post">
<INPUT TYPE = "text" NAME = "in" SIZE = 12>
<INPUT TYPE = "submit" VALUE = "Convert">
</FORM>
 
<HR />
 
<?php
 
$in = NULL;
$in_hb = NULL;
$num = NULL;
 
 
 
// Validates input with Regex.
 
if($_POST["in"] == NULL){
    print "Enter a number or a Hebrew string.";
}elseif(preg_match("/^[1-9][0-9]{0,2}$/",$_POST["in"])){
    $in = $_POST["in"];
}elseif(preg_match("/^[\p{Hebrew} ??]+$/u",$_POST["in"])){
    $in_hb = $_POST["in"];
}else{
    die("illegal input");
}
 
 
 
// Here starts the num2hb logic.
 
if($in <= 999 and $in >= 900){$_900='???';}
elseif($in <= 899 and $in >= 800){$_900 = '??';}
elseif($in <= 799 and $in >= 700){$_900 = '??';}
elseif($in <= 699 and $in >= 600){$_900 = '??';}
elseif($in <= 599 and $in >= 500){$_900 = '??';}
elseif($in <= 499 and $in >= 400){$_900 = '?';}
elseif($in <= 399 and $in >= 300){$_900 = '?';}
elseif($in <= 299 and $in >= 200){$_900 = '?';}
elseif($in <= 199 and $in >= 100){$_900 = '?';}
else{$_900='';}
 
 
 
$_in099 = substr($in,-2);
 
if($_in099 <= 99 and $_in099 >= 90){$_090 = '?';}
elseif($_in099 <= 89 and $_in099 >= 80){$_090 = '?';}
elseif($_in099 <= 79 and $_in099 >= 70){$_090 = '?';}
elseif($_in099 <= 69 and $_in099 >= 60){$_090 = '?';}
elseif($_in099 <= 59 and $_in099 >= 50){$_090 = '?';}
elseif($_in099 <= 49 and $_in099 >= 40){$_090 = '?';}
elseif($_in099 <= 39 and $_in099 >= 30){$_090 = '?';}
elseif($_in099 <= 29 and $_in099 >= 20){$_090 = '?';}
elseif($_in099 <= 19 and $_in099 >= 10){$_090 = '?';}
else{$_090 = '';}
 
 
 
$_in009 = substr($in,-1);
 
if($_in009 == 9){$_009 = '?';}
elseif($_in009 == 8){$_009 = '?';}
elseif($_in009 == 7){$_009 = '?';}
elseif($_in009 == 6){$_009 = '?';}
elseif($_in009 == 5){$_009 = '?';}
elseif($_in009 == 4){$_009 = '?';}
elseif($_in009 == 3){$_009 = '?';}
elseif($_in009 == 2){$_009 = '?';}
elseif($_in009 == 1){$_009 = '?';}
else{$_009 = '';}
 
 
 
if($_in099 == 16){$_099 = '??';}
elseif($_in099 == 15){$_099 = '??';}
else {$_099 = $_090.$_009;}
 
 
 
$_999 = $_900.$_099;
 
if(strlen($_999) > 2){
    $_999g = substr($_999, 0, strlen($_999) -2).'?'.substr($_999, -2);}
else{
    $_999g = NULL;}
 
 
 
// Here starts the hb2num logic.
 
$count = substr_count($in_hb, '?');
$mult = 1 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 2 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 3 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 4 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 5 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 6 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 7 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 8 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 9 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 10 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 20 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 20 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 30 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 40 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 40 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 50 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 50 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 60 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 70 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 80 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 80 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 90 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 90 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 100 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 200 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 300 * $count;
$num = $num + $mult;
 
$count = substr_count($in_hb, '?');
$mult = 400 * $count;
$num = $num + $mult;
 
 
 
// Prints out the results.
 
if(is_null($in) == 0){
    print 'The Hebrew numeral for '.number_format($in).' is:<BR />'.$_999.'<br />'.$_999g;
}elseif(is_null($in_hb) == 0){
    print 'The numerical value for the Hebrew string '.$in_hb.' is '.$num.'.';
}else{
    print "";
}
 
?>
 
</BODY>
 
</HTML>

Re: Gematria Converter

Posted: Thu May 29, 2008 12:53 pm
by dml
You have blocks of code repeated multiple times with only numbers changing. It's the kind of thing one often sees in calculations with tax brackets: this is much more interesting. When you see that kind of repetition, it's a good idea to put the numbers into a data structure which you then loop over: it takes less space, it avoids copy-paste errors, and it means that the data structure can be used for conversions both ways.

Code: Select all

 
// replace Hebrew letters here, can't get them to work in my browser
$letter_values = array(400=>'a', 300=>'b', ..., 2=>'y', 1=>'z') 
 
The conversion, if I understand it correctly, is a matter of looping through and chopping off the biggest letter value you can every time, so you start with say 764, chop off 400 (appending the letter to the result every time you chop its numerical value off) leaving 364, chop off 300 leaving 64, chop off 60 leaving 4, chop off 4, leaving nothing so you're done.

Re: Gematria Converter

Posted: Thu May 29, 2008 5:28 pm
by FrostbyteX
Couldn't you use something like this...?

Untested (at work) but I think the idea is right.

Code: Select all

 
<?php
 
$vals = array(400 => '?',  300 => '?', 200 => '?',100 => '?', 90 => '?', 80 => '?', 70 => '?', 60 => '?', 50 => '?', 40 => '?', 30 => '?', 20 => '?', 10 => '?', 9 => '?', 8 => '?', 7 => '?', 6 => '?', 5 => '?', 4 => '?', 3 => '?', 2 => '?', 1 => '?');
$keys = array_keys($vals);
 
function num2heb($num)
{
    $retval = "";
    for($i = 0; $i < 22; $i++)
    {
        $key = $keys[$i];
 
        while($num > $key)
        {
            $retval .= $vals[$key];
            $num -= $key;
        }
    }
    return $retval;
}
?>
 

Re: Gematria Converter

Posted: Sat May 31, 2008 7:09 am
by veleshanas
Hello dml and FrostbyteX,

Wow, arrays can work wonderful tricks! It goes to show I have a loooot of learning to do about programming.


With the way FrostbyteX coded the algorithm, it seems as if no Hebrew numerals above 500 is necessary. This is really good. However, I cannot seem to get the code working. I expected that the following code returns «aabcd» for «831» but the program gets timed out on Line 16.

What is the problem?? :cry:

Code: Select all

<?php
 
 
$vals = array(400 => 'a', 20 => 'b', 10 => 'c', 1 => 'd');
$keys = array_keys($vals);
 
function num2heb($num)
{
    $retval = "";
    for($i = 0; $i < 4; $i++)
    {
        $key = $keys[$i];
 
        while($num > $key)
        {
            $retval .= $vals[$key];
            $num -= $key;
        }
    }
    return $retval;
}
 
$num = 831;
print num2heb($num);
 
?>

Re: Gematria Converter

Posted: Sat May 31, 2008 8:10 am
by dml
I can't see immediately what it is, but if it timed out, there's probably an infinite loop there: as FrostbyteX said, it's a sketched out solution that wasn't tested.

Print out the values of $num and $key on each loop iteration to see if they're what you expected. Maybe do some checks like throwing an error if they're not numeric.

Re: Gematria Converter

Posted: Mon Jun 02, 2008 8:32 am
by veleshanas
Hello dml,

I've found that the WHILE clause is an infinite loop. Because "print" command cannot print out $key, I'd imagine that detracting that variable from $num never changes the value of $num.

After a very long struggle in front of my PC screen, I got the function work in the following construction.
*It is actually another function that converts Hebrew numerals to numbers. I could not resisting to try a new thing. ;)
**Hebrew letters are replaced by Latin alphabets for simplification.

This suggests that user defined functions cannot read variables outside the function brackets. Or is there any trick that makes it possible? It would be slightly more convenient because the $vals array is used in two functions for my program. [And there are two more similar arrays that are needed by one function only.]

Code: Select all

function heb2num($heb){
 
$vals = array(400 => 'v', 300 => 'u', 200 => 't', 100 => 's', 90 => 'r', 80 => 'q', 70 => 'p', 60 => 'o', 50 => 'n', 40 => 'm', 30 => 'l', 20 => 'k', 10 => 'j', 9 => 'i', 8 => 'h', 7 => 'g', 6 => 'f', 5 => 'e', 4 => 'd', 3 => 'c', 2 => 'b', 1 => 'a');
        foreach($vals as $value => $numeral){
        $num += $value * substr_count($heb, $numeral);
        $heb = str_replace($numeral, '', $heb);
    }
return $num;
}

Re: Gematria Converter

Posted: Mon Jun 02, 2008 9:36 am
by dml

Code: Select all

 
$hebrew_number_mapping = array(...);
function num2heb($num){
  global $hebrew_number_mapping;
  foreach($hebrew_number_mapping as $num=>$letter){
    //...
  }
}
 
The 'global' declaration first thing in the function allows you to use variables not declared inside the function. Since the variable might be referred to from non-adjacent code, it's a good idea to give it a more meaningful name than $vals.

It should be mentioned that there are a lot of ways of misusing global variables. There are good reasons for using one here, but I'd do some research before using them in other contexts.

Re: Gematria Converter

Posted: Mon Jun 02, 2008 8:07 pm
by veleshanas
Thanks! Works perfect. :)

I have just read a few pages of O'Reilly's intro book about PHP and MySQL, where I found a good explanation about defining functions, variable scopes and globals. Everything I needed to know was in the first 40 or so pages. Sigh, I am not very good at systematic learning....