Laskee yhtälön arvon merkkijonosta.
Alunperin tein tämän toista projektia varten, mutta kun homma paisui niin päätin erottaa tämän kokonaan omaksi systeemikseen.
Toki tämänkin voisi regexpien sijaan hoitaa evalilla (kunhan ensin tarkastaa syötteen kunnolla),
mutta päädyin regexpeihin kun niitä pitäisi opetella jokatapauksessa :|
* Tukee kerto-, jako-, plus- ja potenssimerkkejä (^). Lisäksi desimaalitluvut pitää merkitä pisteinä (.), pilkkua (,) ei tueta.
* Antaa debugtietoja halutessa, omaan käyttöön halusin paitsi html:nä myös ihan tekstimuodossa, joten sekin on valittavissa
* Tekee vähän tyhmästi kaikki toiminnot (esim. suorittaa kertolaskuosan vaikkei kertomisia olekaan), vähän tyhmä mutta ehkä versiossa 2 paremmin :|
Edelleen koodia saa käyttää kuten tahtoo, kunhan et vain väitä tätä alkuperäistä koodia omaksesi.
Versio 2.0, 22.07.2005:
*Korjattu bugi jossa muut muuttujat kuin x eivät toimineet
*Korjattu bugi jossa tuli virhe kutsuttaessa funktiota useaan kertaan
<?php
/*
Laskee yhtälön arvon stringistä.
Alunperin tein tämän toista projektia varten, mutta kun homma paisui niin päätin erottaa tämän kokonaan omaksi systeemikseen.
Toki tämänkin voisi regexpien sijaan hoitaa evalilla (kunhan ensin tarkastaa syötteen kunnolla),
mutta päädyin regexpeihin kun niitä pitäisi opetella jokatapauksessa :|
* Tukee kerto-, jako-, plus- ja potenssimerkkejä (^). Lisäksi desimaalitluvut pitää merkitä pisteinä (.), pilkkua (,) ei tueta.
* Antaa debugtietoja halutessa, omaan käyttöön halusin paitsi html myös ihan tekstimuodossa, joten sekin on valittavissa
* Tekee vähän tyhmästi kaikki toiminnot (esim. suorittaa kertolaskuosan vaikkei kertomisia olekaan), vähän tyhmä mutta ehkä versiossa 2 paremmin :|
Edelleen koodia saa käyttää kuten tahtoo, kunhan et vain väitä tätä alkuperäistä koodia omaksesi.
Versio 2.0, 22.07.2005:
*Korjattu bugi jossa muut muuttujat kuin x eivät toimineet
*Korjattu bugi jossa tuli virhe kutsuttaessa funktiota useaan kertaan
*/
function laskestring($laskutoimitus, $luku, $muuttuja = "x", $debug = false, $debughtml = true) {
//Poistetaan turhat välilyönnit alusta ja lopusta, samoin muutetaan useiden välilyöntien sarjat vain yhdeksi välilyönniksi
$laskutoimitus = preg_replace("/[ ]+/", " ", trim($laskutoimitus));
//Hyväksytään vain laskutoimitusmerkit sekä numerot ja välilyönnit
$laskutoimitus = preg_replace("/[^\\+\\-\\/\\*\\^\\(\\)\\.{$muuttuja}0-9 ]/", "", $laskutoimitus);
//Tarkastetaan että sulkeiden aloitusmerkkejä on yhtä paljon kuin sulkemismerkkejä, mutten palautetaan error
if (substr_count($laskutoimitus, "(") != substr_count($laskutoimitus, ")")) {
if ($debug)
echo "Sulkujen määrä ei täsmää, tarkasta että olet sulkenut kaikki sulkeet\n";
if ($debughtml)
echo "<br />";
return false;
}
//Tämä suorittaa itse laskun, tälläinen järjestely sulkujen takia,
//aloitusviestillä voi antaa ensimmäisen viestin jossa näytetään laskettava lauseke
if (!function_exists("suoritalasku")) {
function suoritalasku($laskutoimitus, $luku, $muuttuja = "x", $debug = false, $debughtml = false, $aloitusviesti = "Laskutoimitus") {
//Aloitustilanne debugtulostusta varten
$debugtulostus[$aloitusviesti] = $laskutoimitus;
//Sallitut laskumerkit
$laskumerkit = "[\\+\\-\\/\\*\\^]";
//Tarkistetaan hieman syntaksia
//Aloitus
if (preg_match("/^([\\+\\/\\*\\^])/", $laskutoimitus, $virhe)) {
$debugtulostus['Virheellinen aloitus'] = $virhe[0];
$virheitä = true;
}
//Lopetus
if (preg_match("/($laskumerkit)$/", $laskutoimitus, $virhe)) {
$debugtulostus['Virheellinen lopetus'] = $virhe[0];
$virheitä = true;
}
//Laskutoimitukset
if (preg_match("/($laskumerkit)[ ]?($laskumerkit)/", $laskutoimitus, $virhe)) {
$debugtulostus['Virheellinen laskutoimitus'] = $virhe[0];
$virheitä = true;
}
//Muuten ei virhettä, tehdään laskutoimitukset
if (!$virheitä) {
//Muunnetaan merkinnät 2x muotoon 2 * x
$debugtulostus['Muunnos'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?$muuttuja/", "\\1 * $muuttuja", $laskutoimitus);
//Sijoitetaan muuttuja
$debugtulostus['Muunnos'] = $laskutoimitus = preg_replace("/$muuttuja/", $luku, $laskutoimitus);
//Lasketaan potenssit
$debugtulostus['Potenssi'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\^[ ]?([0-9.]+)/e", "pow(\\1, \\2)", $laskutoimitus); //Korottaa potenssiin
//Lasketaan kerto- ja jakolaskut
while (!$exit) {
$edellinen = $laskutoimitus;
$debugtulostus['Kertominen'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\\*[ ]?([0-9.]+)/e", "\\1 * \\2", $laskutoimitus); //Kertominen
$debugtulostus['Jakaminen'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\\/[ ]?([0-9.]+)/e", "\\1 / \\2", $laskutoimitus); //Jakaminen
//Mikäli ei ole enään jako- tai kertomerkkejä, tai loop on jäänyt junnaamaan (edellinen arvo sama kuin nykyinen) poistutaan while-silmukasta
if (strpos($laskutoimitus, "/") == false && strpos($laskutoimitus, "*") == false or $edellinen == $laskutoimitus)
$exit = true;
}
}
//Exitiä käytetään vielä toisessa loopissa
unset($exit);
//Lasketaan plus- ja miinuslaskut
while (!$exit) {
$edellinen = $laskutoimitus;
if (strpos($laskutoimitus, "-") === 0)
$debugtulostus['Ynnäys'] = $laskutoimitus = preg_replace("/\\-[ ]?([0-9.]+)[ ]?(\\+|\\-)[ ]?([0-9.]+)/e", "-\\1 \\2 \\3", $laskutoimitus);
else
$debugtulostus['Ynnäys'] = $laskutoimitus = preg_replace("/^[ ]?([0-9.]+)[ ]?(\\+|\\-)[ ]?([0-9.]+)/e", "\\1 \\2 \\3", $laskutoimitus);
if (!strpos($laskutoimitus, "+") && !strpos(substr($laskutoimitus, 1), "-") or $edellinen == $laskutoimitus)
$exit = true;
}
//Tulostetaan debugit jos käyttäjä niin haluaa
if ($debug) {
if ($debughtml)
echo "<pre>";
foreach ($debugtulostus as $toiminto => $laskutoimitus) {
if ($debughtml)
echo "$toiminto: \t $laskutoimitus\n";
else
echo "$toiminto: $laskutoimitus \n";
}
if ($debughtml)
echo "</pre>";
}
//Palautetaan vastaus mikäli laskutoimitukset meni ilman virheitä
if (!$virheitä)
return $laskutoimitus;
else {
return "false"; //Purkkaa ehkäpä,
//palautetaan string false ja tarkastetaan sen sijainti itse koodissa alla, tämä siksi että
//palautus tulee regexpin evaliin josta en osaa sen totuusarvoa tarkastaa :|
}
} //suoritakoodi()
}
//Annetaan se kaikkein alkuperäisin jos debugataan
if ($debug) {
if ($debughtml)
echo "<b>Alkuperäinen muoto:</b> <code>$laskutoimitus</code> \n";
else
echo "Alkuperäinen muoto: $laskutoimitus \n";
}
//Sulkujen sisältä lasketaan ensin laskut
while (!$exit) {
$edellinen = $laskutoimitus;
$laskutoimitus = preg_replace("/\\([ ]?([^\\(]*?)[ ]?\\)/e", "suoritalasku('\\1', $luku, $muuttuja, $debug, $debughtml, 'Suluista')",$laskutoimitus);
if (strpos($laskutoimitus, "false") != false)
return false;
//Ja taas tätä loputonta debuggauskoodia
if ($debug) {
if ($debughtml)
echo "<br />\n<b>Sulut poistettu, uusi muoto:</b> <code>$laskutoimitus</code>"."<br />\n";
else
echo "\nSulut poistettu, uusi muoto: $laskutoimitus"."\n";
}
//Mikäli on sulkuja vielä, tai looppi jää jostain syystä jauhamaan tyhjää keskeytetään se
if (strpos($laskutoimitus, "(") == false && strpos($laskutoimitus, ")") == false or $edellinen == $laskutoimitus)
$exit = true;
}
//Sitten kun sulut on poistettu niin lasketaan loputkin
$laskutoimitus = suoritalasku($laskutoimitus, $luku, $muuttuja, $debug, $debughtml);
//Palautetaan vastaus mikäli laskutoimitukset meni ilman virheitä
if (!$virheitä && is_numeric($laskutoimitus))
return $laskutoimitus;
else
return false;
}
//Esimerkki
if (!$_GET['laskutoimitus'])
$laskutoimitus = "((((-5 * 5) + (7x)) * 3.5) - 2) ^ 2";
else
$laskutoimitus = $_GET['laskutoimitus'];
if (!$_GET['luku'])
$luku = 5;
else
$luku = $_GET['luku'];
echo "\nVastaus: ".laskestring($laskutoimitus, $luku, "x", 1, 1);
?>En testannut, mutta kyllä tuosta on hyötyä tehdä se muullakin kuin evalilla, koska epä-scriptikielissä ei ole eval funktiota lainkaan :)
Vielä kun tekisi ilman regexpejä niin voisi soveltaa helposti kaikkiin kieliin.
Onhan tuo hienoa viritellä regexpeillä mutta homma menisi hieman nätimmin (ja laajennettavammin) ihan vain tekemällä pinon ja se siitä...
Aihe on jo aika vanha, joten et voi enää vastata siihen.