Zdravím. Tak tohle je výzva pro mě i pro všechny logicky myslící lidi. Na programovacím jazyku ani tak nezáleží, ale já to píšu v php. Nejdříve abych vysvětlil okolnosti/kontext a kód který jsem použil, ale je to poměrně dlouhé, tak nevím jestli to vůbec někdo bude číst až do konce. Jádro problému (shrnuto tučným písmem dole) je až na konci (poslední dvě čáry)
Mám metodu, která načítá soubor do zásobníku po jednom řádku. Při každém novém řádku se přičte hodnot +1 do proměnné n.
$n++
Potom spouštím metodu, která má za úkol omezit zásobník na minimum. Je to dané podle určitých hledacích kritérií, která jsou definovány v poli, ležícím mimo funkci. K tomu je klíčové použít toleranci. Metoda přijímá argument $n a leží v cyklu načítání toho souboru. Navíc leží zanořena v dalším cyklu, který prochází několik slov, která hledám.
Dejme tomu, že máme načteno 71 řádků, a poslední řádky jsou tyto:
#69 - modrá polička
#70 - pěkné auto
#71 - růžové triko
(čísla jsou čísla řádků a to v zásobníku není; načítání řádků pak bude pokračovat)
Vysvětlím metodu na příkladu. Podle aktuálních argumentů a kritérií, metoda pracuje s podmínkami takto:
Jsem zrovna na řádku $n 70 a hledám první slovo (auto). Auto má nastavenu toleranci 0 řádků. Metoda vrátí řetězec
pěkné auto
Další příklad:
Jsem zrovna na řádku $n se rovná 70 a hledám větu, která začíná na "polička" a končí na "auto". Toto vyhledávací kriterium má toleranci 1. Vypočítám toleranci jako $tolerance=$n-1;
polička
pěkné auto
Snad je to až doposud jasné.
Takže to shrnu, stručně to vypadá asi takto:
while (!feof ($fd)){ // CYKLUS
$line = fgets($fd); // NAČÍTÁNÍ ŘÁDKŮ
$buffer .= $line; // UKLÁDÁNÍ DO ZÁSOBNÍKU
for ($i = 0; $i<$this->conf->multiline_search->items_count;$i++) // HLEDÁM SLOVA ZADANÁ V KONFIGURACI
$this->mySearchEngine($buffer, $index, $n); // TOTO JE MOJE METODA NA HLEDÁNÍ
}
Metoda pak používá různé statické proměnné, které uchovávají hodnoty proměnných po skončení metody pro další použití při dalším volání.
A teď se dostávám k jádru problému a to je správný výpočet okamžiku, kdy se má tolerance uplatnit. Jelikož pokud jsem prošel několik řádků a žádný výskyt jsem tam nenašel, nechci se k této staré části vracet.
Kdybych použil rovnou toleranci, která je nastavena pro daný hledaný výraz v konfiguráku, tak výsledek může být, že se prohledává část zásobníku která nemá být hledána.
Příklad:
- Jsem na řádku #70, tolerance je 0 (hledání na současném řádku), hledám slovo auto.
- našel jsem "auto" a vracím řetězec
- jdu na další řádek a provádím hledání pro další výraz ("triko") a mám toleranci 9. Tzn. omezím své hledání v zásobníku na #71-9, tedy řádky #62-71. Tím pádem nesmyslně načítám 8 řádků a hledání se zbytečně komplikuje. Potřebuju prohledat jen dva řádky. samozřejmě, že místo textu "triko" v reálu je text na dva řádky, atp.
Mám na to tento mechanismus:
$tolerance = $this->c->multiline->SearchLimit['before_strings'][$index]; // předběžná hodnota if ($last_tolerance < $tolerance){
if ( $allow_set_tolerance == true ){
$last_tolerance++; // přičíst pouze jednou / když spouštím cyklus poprvé
$allow_set_tolerance = false;
}
$tolerance=$last_tolerance;
if ($last_tolerance+1 == $tolerance) $tolerance = $this->c->multiline->SearchLimit['before_strings'][$index];
}
else if ($last_tolerance >= $tolerance) {$last_tolerance = $tolerance;
}
To co se děje v tomto kódu je postupné navyšování tolerance od 0 do 9. S každým novým řádkem se zvýší tolerance o jedna. Tím pádem se nemá prohledávat to co již bylo prohledáno. Budu pak prohledávat nejdříve 1 řádek navíc, pak 2 řádky, 3 řádky, atd. dokud nenajdu co hledám. Kdyby tolerance byla 0, tak se na hledání vykašlu hned po prvním řádku.
Předchozí algoritmus ještě vyžaduje napočítat kdy se smí připočítávání/navyšování tolerance povolit:
public function mySearchEngine(&$buffer, $index, $n, $sensitive = "i") {
static $last_tolerance;
static $allow_set_tolerance; // pokud tolerance byla nastavena, nepovolit v cyklu na jednom řádku další nastavování tolerance
static $old_n; // pamatuje jestli byl načten nový řádek
static $old_n_2; // pokus
static $n_arr; // pamatuje jestli byl načten nový řádek
$newline = ($old_n +1==$n) ? true : false; // zjišťuje zda byl načten nový řádek
if ($newline){ $old_n = $n; } // nastavit tuto hodnotu pouze pro nový řádek $n, tj. pro hlavní cyklus, ne pro ten druhý vnořený cyklus; jinak by se to přičítalo při procházení hledaných slov
Poznámky:
$old_n - ukládá staré $n, abych dokázal rozpoznat, kdy došlo k přechodu na nový řádek.
Jde o to, že pokud jsem právě přešel na nový řádek, který chci prohledat a tolerance je 0, nebudu nastavovat toleranci 9 ale 1. Výsledek ale není ideální. Protože výsledkem jsou tři řádky
#69 - modrá polička
#70 - pěkné auto
#71 - růžové triko
místo dvou:
#70 - pěkné auto
#71 - růžové triko
Pokud jsem ve výše uvedeném kódu někde udělal chybu (snad ne, ale je to stará verze), tak současný kód je takto, pomocí pole:
public function mySearchEngine(&$buffer, $$index, $n) {
static $last_tolerance;
static $allow_set_tolerance; // pokud tolerance byla nastavena, nepovolit v cyklu na jednom řádku další nastavování tolerance
static $n_arr; // pamatuje jestli byl načten nový řádek
$newline = ($n_arr[0]+1==$n) ? true : false; // zjišťuje zda byl načten nový řádek
$nextline = ($n_arr[1]+1==$n) ? true : false; // pomáhá vymezit rozsah řádků
if ($nextline){
$n_arr[1] = $n_arr[0]; // nastavit na ještě starší hodnotu $n. Když $n je 70, $n_arr[0] je 69 a $n_arr[1] mý být 68
}
$n_arr[0] = $n;
$n_arr[0] - staré $n (předchozí cyklus)
$n_arr[1] - staré $n (z předpředchozího cyklu )
Hledám řešení jak zjistit správný okamžik, kdy se má navyšování tolerance povolit. Je to nastavené na jeden cyklus později, a to funguje, ale potřebuju to opozdit o dva cykly a to nefunguje.