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.