Autor Zpráva
radekt
Profil
Dobrý den, potřebuji regulérními výrazy ze souboru vytáhnout tagy h2 a to, co je mezi nimi. Zvenku to funguje:
<?php

$text = file_get_contents('soubor');

if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup)) {

    foreach ($vystup[0] as $m) echo $m;
}

?>

Ale já to potřebuji provádět uvnitř souboru a když použiji $text = file_get_contents($_SERVER['PHP_SELF']);, vrátí mi to: [function.file-get-contents]: failed to open stream: No such file or directory in soubor.php on line 4.
Alphard
Profil
Aby script parsoval sám sebe? To vypadá na hodně zvláštní návrh, nechcete raději aplikační a obsahovou vrstvu oddělit?
DJ Miky
Profil
PHP_SELF začíná lomítkem vzhledem k rootu webu, když to použiješ přímo jako název souboru, pak /soubor.php znamená soubor z rootu disku, který tam samozřejmě není.

Místo toho se dá použít magická konstanta __FILE__ (dvě podtržítka z každé strany), která obsahuje celou absolutní cestu k souboru. Tedy:
file_get_contents(__FILE__)

Ovšem je to trochu podivné řešení, jak už píše Alphard.
radekt
Profil
Dobrý den, je to podivné řešení, ale potřebuji to k tomu, abych měl v článku pod hlavním nadpisem nejprve seznam kapitol a pak aby pokračoval vlastní text. Děkuji moc za radu, nyní jsem kód upravil podle rady takto:
<h1>Nadpis</h2>
<p>Obsah:</p>
<?php

$text = file_get_contents(__FILE__);

if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup)) {

    foreach ($vystup[0] as $m) echo $m;
}

?>
<br>

<h2>Kapitola 1</h2>
<p>nějaký text</p>
<h2>Kapitola 2</h2>
<p>nějaký text</p>
<h2>Kapitola 3</h2>
<p>nějaký text</p>
<h2>Kapitola 4</h2>

pak si ještě pohraji s kotvami, atd. ale až později. Teď mi to vrací to, co potřebuji, ale za slovo obsah ještě dá (.*?) z regulárního výrazu - jak se toho (.*?) mám ve výpisu zbavit? S regulárními výrazy se teprve seznamuji.
Děkuji
radekt
Profil
O něco jsem pokročil:
<h1>Nadpis</h2>
<p>Obsah:</p>
<?php
 
$text = file_get_contents(__FILE__);
 
// proměnná pro cyklus na výpis obsahu s odkazy
$cislo_kapitoly=0;
// proměnná pro kotvy ve vlastním dokumentu
$kotva = 0;
 
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup))
{
    foreach ($vystup[0] as $m)
    {
                  // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (!StrPos(" ".$m, '(.*?)'))
        {
            $cislo_kapitoly++;
            echo '<a href=#'.$cislo_kapitoly.'>'. strip_tags($m).'</a><br>';
        }
    }
}
 
?>
<br>
 
<a id="<?php $kotva++; echo $kotva; ?>"><h2>Kapitola 1</h2></a>
<p>nějaký text</p>
<a id="<?php $kotva++; echo $kotva; ?>"><h2>Kapitola 2</h2></a>
<p>nějaký text</p>
<a id="<?php $kotva++; echo $kotva; ?>"><h2>Kapitola 3</h2></a>
<p>nějaký text</p>
<h2 id ="<?php $kotva++; echo $kotva; ?>">Kapitola 4</h2>
<p>nějaký text</p>
Už jsem téměř spokojen, ale nevím, proč regulární výraz nevrátí kapitolu 4, tj. tam, kde je tag s atributy - a raději bych měl kód <h2 id="atribut">, než ho ještě obalovat do <a>. Můžete někdo poradit?
Tori
Profil
Asi vám to rozbije funkce strip_tags. Tohle by mělo jít, změny zvýrazněny:
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup))
{
    foreach ($vystup[1] as $m)
    {
                  // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.$m.'</a><br>';
        }
    }
}
radekt
Profil
Dobrý den,
děkuji, perfektní, funguje, jenom se chci zeptat - proč se pole prohledává od prvního a ne od nultého? To mi není jasné.
Děkuji
Tori
Profil
radekt:
To není "od prvního prvku" ale "první podvýraz" - tedy ta část v závorkách. Nechte si před cyklem vypsat proměnnou $vystup, ať vidíte, co přesně preg_match_all vrací. A zkuste si taky přidat jako 4. parametr konstantu PREG_SET_ORDER, bude to vracet jinak seskupené pole, jakoby o 90° otočené - někdy se víc hodí tohle.
radekt
Profil
dal jsem tento kód:
preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup);
echo $vystup."<br>";
preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup, PREG_SET_ORDER);
echo $vystup;
a vypsalo to:
Array
Array
Asi to chápu špatně, ale měl jsem za to, že se vše mezi tagy řadí do nultého až posledního pole - tedy nulté je <h2.*>(.*?)</h2>, první je <h2>Kapitola 1</h2>, druhé <h2>Kapitola 2</h2> atd. Takže jsem se domníval, že jde vypisovat od nultého pole, které se vyloučí podmínkou. Ale když jsem dal v kódu foreach ($vystup[0] as $m) nevrátilo to nic.
Tori
Profil
Místo echo použijte var_dump, je to dvourozměrné pole.
radekt
Profil
Výborně, už to chápu, díky za pomoc. Uvažoval jsem i o DOMDocument(), ale toto se mi zdá elegantnější. Zajímalo by mně, jestli ještě někdo řešil takovýto problém a jak. Ještě jednou díky moc.
radekt
Profil
Kvůli "kosmetice" stránek jsem udělal ještě jednu změnu, a to, aby se obsah negeneroval v případě, že v článku bude jen jedna kapitola:
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup) && count($vystup[1])>2)
{
    echo 'Obsah:<br>';
    foreach ($vystup[1] as $m)
    {
        // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.$m.'</a><br>';
        }
    }
}
radekt
Profil
Když jsem celý kód obsah.php:
<?php

$text = file_get_contents(__FILE__);

// proměnná pro cyklus na výpis obsahu s odkazy
$cislo_kapitoly=0;
// proměnná pro kotvy ve vlastním dokumentu
$kotva = 0;

// parsování textu mezi tagy h2
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup) && count($vystup[1])>2)
{
    echo 'Obsah:<br>';
    foreach ($vystup[1] as $m)
    {
        // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.$m.'</a><br>';
        }
    }
}
includoval do článku, výpis kapitol mi nevrátil - parsuje jen sám sebe, ne i soubor, do kterého je includován. Musel jsem to řešit tak, že jsem z kódu obsah.php vyjmul řádek $text = file_get_contents(__FILE__); a vložil jej do samotného článku před voláním include "obsah.php". Nyní všd funguje tak, jak má.
radekt
Profil
Dobrý den,
všechno funguje výtečně, až na jednu věc. Když je v textu H2 vnořený tag, konkrétně - <h2 id = "10">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</h2>, vrátí se mi při generování seznamu kapitol tímto způsobem jen <a href="#10">10. do Moesie, povstání v Pontu</a>.
Keeehi
Profil
if (preg_match_all('~<h2[^>]*>(.*?)</h2>~', $text, $vystup) && count($vystup[1])>2)
Sice to není 100%, ale myslím, že byste na to neměl narazit.

Nebo použít původní dotaz a pak $vstup[0] a na něj aplikované strip_tags(). Zbavíte se tak toho odkazu (stejně to musíte udělat když to má pak sloužit jako kotva), ale celý text zůstane.
radekt
Profil
tento výraz mi vrátil <a href="#10">10. ">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</a>. Začínám se v těch reg. výrazech ztrácet
Keeehi
Profil
radekt:
Je to nějaké divné. ve vstupním řetězci se 10. nevyskytuje, přesto je ve výstupním obsažen.

if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup) && count($vystup[1])>2)
{
    echo 'Obsah:<br>';
    foreach ($vystup[0] as $m)
    {
        // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.strip_tags($m).'</a><br>';
        }
    }
}
radekt
Profil
Omlouvám se, ještě jsem u sebe na pc modifikoval kód tak, aby ve výpisu bylo vidět číslo kapitoly a sem jsem to nedal:
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup) && count($vystup[1])>2)
{
    echo 'Obsah:<br>';
    foreach ($vystup[0] as $m)
    {
        // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.$cislo_kapitoly.'. '.$m.'</a><br>';
        }
    }
}
radekt
Profil
Tak už vážně nevím. Ještě jsem zkoušel na $vstup[0] aplikovat strip_tags(), jak mi bylo doporučeno, ale tam jsem také pohořel - buď se pro chyby vztekal foreach nebo var_dump.
radekt
Profil
Další pokus, ale postup jen o slepičí krok. Pokoušel jsem se vyloučit tagy odkazů, ale tento výraz:
preg_match_all("'<h2.*>[^a href.*?>$</a>](.*?)</h2>'", $text, $vystup)
mi z odkazu
<h2 id = "10">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</h2>
vygeneroval toto:
<a href="#10">áků</a> do Moesie, povstání v Pontu</a>
Ach jo
radekt
Profil
Rekapitulace:
Tento kód:
<h1>Nadpis</h2>

<?php
$text = file_get_contents(__FILE__);

// proměnná pro cyklus na výpis obsahu s odkazy
$cislo_kapitoly=0;
// proměnná pro kotvy ve vlastním dokumentu
$kotva = 0;

// parsování textu mezi tagy h2
// provede se, pokud je více než jedna kapitola, tj. výskyt párových tagů h2 více než 2 
// počítá se i výraz hodnocený fcí preg_match_all, protože soubor páruje sám sebe
if (preg_match_all("'<h2.*>(.*?)</h2>'", $text, $vystup) && count($vystup[1])>2)
{
    echo 'Obsah:<br>';
    foreach ($vystup[1] as $m)
    {
        // vyloučení řetězce (.*?), protože soubor parsuje sám sebe
        if (StrPos($m, '(.*?)') === false)
        {
            $cislo_kapitoly++;
            echo '<a href="#'.$cislo_kapitoly.'">'.$cislo_kapitoly.'. '.$m.'</a><br>';

        }
    }
}

?>
<br>


<h2 id ="<?php $kotva++; echo $kotva; ?>">Kapitola 1</h2>
<p>tttt</p>
<h2 id ="<?php $kotva++; echo $kotva; ?>">Kapitola 2</h2>
<p>xxxx</p>
<h2 id = "<?php $kotva++; echo $kotva; ?>">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</h2>
?>

vrátí pro poslední kapitolu toto: <a href="#3">3. do Moesie, povstání v Pontu</a><br><br>
z důvodu nenasytnosti reg. výrazu, který se zastaví až u uzavírací závorky > tagu </a>. Změním-li reg. výraz na preg_match_all("'<h2.*?>(.*?)</h2>'", tak se pro změnu zastaví moc brzy - u uzavírací závorky tagu pro php, takže vrátí toto:
3. ">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</a>

Kód s vystup[0] místo vystup[1] vrátí v obou variantách toto:
<h2 id = "<?php $kotva++; echo $kotva; ?>">Vpád <a href="http://antika.avonet.cz/article.php?ID=1601">Dáků</a> do Moesie, povstání v Pontu</h2>
Když se pokouším vyhodit tagy:
echo '<a href="#'.$cislo_kapitoly.'">'.$cislo_kapitoly.'. '.strip_tags($m).'</a><br>';
vyhodí to text úplně a vrátí:

Obsah:<br><a href="#1">1. </a><br><a href="#2">2. </a><br><a href="#3">3. </a><br><br>

Jak použít strip_tags na vystup[0], na to jsem nepřišel. Už jsem vyzkoušel všechno možné a rezignuji - vyházím prostě vnořené tagy <a> a bude to fungovat
radekt
Profil
Takže jsem to nakonec vyřešil takto (a dosti čuňácky):
$cislo_kapitoly++;
// vyloučení tagu odkazu - začátek
$m = preg_replace('"<a href.*?>"',"",$m);
// vyloučení tagu odkazu - konec
$m = preg_replace('"</a>"',"",$m);
// <h2.*> je moc nenasytný a zastaví se až za odkazem - zmizí text mezi tagy odkazu
// to samé s otazníkem se naopak zastaví moc brzy - u uzavírací značky php, takže je nutno vyloučit řetězec ">
$m = preg_replace('"\">"',"",$m);
echo '<a href="#'.$cislo_kapitoly.'">'.$cislo_kapitoly.'. '.$m.'</a><br>';
radekt
Profil
Druhá varianta je použití strip_tags:
$m = strip_tags($m, '<h2>');
$m = preg_replace('"\">"',"",$m);
echo '<a href="#'.$cislo_kapitoly.'">'.$cislo_kapitoly.'. '.$m.'</a><br>';
Když jsem se pokoušel použít fci fgetss() - ta má odstranit jak html, tak php značky, což by bylo nejčistší, neuspěl jsem, vždy naskočila hláška expects parameter 1 to be resource, string given.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: