Autor Zpráva
honky tonk
Profil *
Potřeboval bych nějak zkrátit řetězec $string o 1411 řádků které obsahují html kód . Jak to co nejefektivnějji udělat?
Alphard
Profil
Ten popis je dost vágní. Jesti znáte-li např. pozice hranic, lze použít substr(), substr_replace() atd. Záleží na situaci.
Micruss
Profil
šlo by to takto ::::

<?php

$string = "1411 řádků a více...";

$w = explode("\n", $string);
$w = explode($w[1410], $string);
$string = $w[0]; # text před 1411
echo $string;
Alphard
Profil
Micruss [#3]:
Méně optimální cesta vás nenapadla? :-) Vytváříte mnohatisiciprvkové pole jen abyste nakonec znovu v textu hledal jakýsi řetezec, o kterém docela naivně věříte, že je unikátní?
Neberte to špatně, jen chci poukázat na značné nedostatky toho algoritmu.
honky tonk
Profil *
Alphard:
pozice hranice neznám. nenapadá mě nic jiného než to řešit ručně pomocí smyčky for. Budu tedy načtený sdrojový text procházet po jedné a počítat výskyt \r\n

Micruss
právě explode jsem se chtěl vyhnout.
Tori
Profil
honky tonk:
Chcete odmazat 1411 řádků od začátku nebo od konce?
honky tonk
Profil *
Tori:
Od začátku. Co tak to stáhnout od pozice 1441 to by snad šlo ne?

$handle = fopen("http://www.example.com/", "rb");
$contents = '';
fseek($handle,1141)
while (!feof($handle)) {
  $contents .= fread($handle, 8192);
}
fclose($handle);


Nevíte náhodou proč mi nejde vrátit velikost souboru?
Snažím se načíst soubor, který je otevřený, ale filesize pořád vrací 0. Ale soubor existuje - cesta folder/temp.html


          $fh=fopen($file,"r");
                die(filesize($file)."");
            $html=fread($fh, filesize($file) );    
Tori
Profil
IMHO pokud neznáte přesný offset, tak tím cca jedním kilobajtem při stahování nic neušetříte. Když se kouknete do zdrojáku toho stahovaného souboru, podle čeho poznáte, kde končí těch x řádků? Dalo by se vyhledat nějakou část HTML kódu, konec prvku s určitým ID apod.
Alphard
Profil
honky tonk:
Konečně popis problému, se kterým se dá pracovat. Původní dotaz byl k ničemu. Pořád by to ale šlo vylepšit, viz [#8] Tori.

Ke kódu [#7]. fseek() vůbec neřeší řádky, bere bajty. Zkuste využít fgets().

$i = 0;
while (($s = fgets($handle)) !== false)
{
  if ($i++ > 1141)
  {
   $string .= $s; // jestli je soubor hodně dlouhý, šlo by tady hned zapisovat do jiného souboru
  }
}
honky tonk
Profil *
Myslel jsem že bych tím že to oseknu zkrátil proces vyhledávání (v tomto smyslu bych něco ušetřil, ale ne bajtů). Tak pomocí regulárního výrazu bych to zvládl taky, ale teď potřebuju vyřešit ten filesize protože bez toho se nehnu abych to dořešil. Nejde mi otevřít stažený soubor.


Už to mám otevřené.


Vyřešil jsem to takto
preg_match_all("@\.\w\w\w\w{display:inline}@", $data, $matches, PREG_OFFSET_CAPTURE);
print_r($matches);

Výsledek:
http://paste.ofcode.org/mCx9GXyCTWxKpLHdNPFk9C


Nebo vlastně takto:
preg_match_all("@(?<=\.)\w\w\w\w(?={display:inline})@", $data, $matches, PREG_OFFSET_CAPTURE);
mi to vrátí jen 4 znaky název třídy a ofset nalezeného stringu. Je to skvělé řešení.
Micruss
Profil
No abych pravdu řekl, tak mě vytvoření tisicového pole vůbec nenapadlo v té době, psal jsem to jako první nápad... ;) příště by to chtělo se nd tím více zmyslet ;)
honky tonk
Profil *
Ještě se s vámi podělím o komplikace. Tak nejdříve jsem si uvědomil, že těch stylů, které hledám může být v daném bloku více. Blokem myslím určitý úsek od prvního výskytu daného stylu. Ten úsek se pohybuje zhruba mezi 1000 a 1452 znaky. Takže nejdříve jsem potřeboval spočítat styly. Napsal jsem teda tuto funkci:

http://paste.ofcode.org/GLqDYy6ZHjekM6UJbsD3RR

Výsledky pak zpracovávám takto:
foreach ($originalMatches[0] as $arr):
  $i++;
  $boundStylesCount = testRepeat($originalMatches,$i,$minBlockLength,23);

čímž zpočítám kolik stylů daného typu se vyskytuje v tom bloku. Jednotlivé bloky totiž spolu nesouvisí.

Pak ale může vzniknout další situace: od pozice prvního výskytu hledám pomocí preg_match zase ten styl, ale protože jsou ty styly 3 tak musím použít smyčku:
   for ($c=0; $c<$boundStylesCount; $c++){ // anchor: styles found in this block:
      preg_match("@(?<=class=\"".$originalMatches[0][$c]."\">)\d{1,3}(?=<)@", $data, $matches, PREG_OFFSET_CAPTURE, $begin);
      if ( isset($matches[0][1]) )
             {
          $diff=$matches[0][1]-$begin;
              if ( $diff<$maxBlockLength )
                       $results[$diff]=$matches[0][1];
        
         }
   }// END for
Ještě ale nastal problém - co když je tam těch výsledků více? Dejme tomu styl abcd má 2 výsledky. Ale do pole $results dostanu jen jeden, protože jsem nepoužil preg_match_all. Když bych použil preg_match_all tak zase se bude prohledávat celý dokument až do konce což je zbytečná zátěž. Ideální by bylo kdyby se dala nastavit délka bloku ve kterém hledat, ale to nejspíš nejde... Co s tím?
Tori
Profil
honky tonk:
Tak nejdříve jsem si uvědomil, že těch stylů, které hledám může být v daném bloku více. Blokem myslím určitý úsek od prvního výskytu daného stylu. Ten úsek se pohybuje zhruba mezi 1000 a 1452 znaky.
Ještě jednou: Podle čeho poznáte, že tento styl hledáte? Totiž jestli skutečně parsujete takovýhle výstup z var_dump, tak by bylo podstatně jednodušší to prostě pomocí preg_replace přeformátovat na takový formát, který se nějakou funkcí dá převést na normální pole. A pak použít array_filter nebo něco podobného, čím z toho dostanete požadované prvky. edit: pardon, přehlédla jsem, že to je výsledek. Jenže pořád nevíme, podle jakého klíče poznáte, že tuto třídu chcete a tuhle ne, takže není co poradit.
honky tonk
Profil *
Tori:
Poznám to během parsování výsledků. Spočítám si kolik stylů leží ve stejném bloku, která má určitou délku. To je to:
$boundStylesCount = testRepeat($originalMatches,$i,$minBlockLength,23);
Ten druhý problém se týká hledání v tomto bloku. Napadlo mě teď použít substr, sice jsem se chtěl této funkci vyhnout kvůli kopírování bytů, na druhou stranu je ale stále lepší zkopírovat 1452 bytů a ty prohledat pomocí preg_match_all než použít preg_match_all na celý dokument. Jako já už to skoro mám, protože ty podmínky co jsem použil na hledání jsou naštěstí jednoduché a block je taky snadno k nalezení. Jen ještě jednou zvážit jestli není ještě třetí možnost, která by nevyžadovala kopírovat ten block. Ale tuším že asi ne, protože samo o sobě preg_match_all s flagem PREG_OFFSET_CAPTURE a offsettem z minulého hledání je dost geniální. Hold tvůrci PHP zapoměli taky udělat omezení té zdrojové délky (offsetEnd).
Alphard
Profil
Kdybyste ukázal vstup a řekl, co z něj potřebujete, mohl byste si ušetřit ty monology. Přečtěte si svůj popis a zapomeňte vše, co nebylo uvedeno. Poradil byste sám sobě?
honky tonk
Profil *
Alphard:
Tak já jsem na všechna řešení nakonec přišel sám. Částečně díky vyhledávači.
honky tonk
Profil *
Napadá vás proč tento příkaz nefunguje?

preg_match_all("@class=\"\d{1,3}\">\d{1,3}(?=<)@", $block, $matches, PREG_OFFSET_CAPTURE, 0);
for($c=0; $i<count($matches[0]); $c++)
      $matches[0][$c][0] = preg_replace("@class=\"\d{1,3}\">@", "", $matches[0][$c][0]);
print_r($matches);

Snažím se odstranit class="???"> z pole výsledků:
http://paste.ofcode.org/JEDBnEvvjQeQ2cYaVYCBbW
Tori
Profil
A co ta proměnná $i, nevzniká vám nekonečná smyčka náhodou?
honky tonk
Profil *
Tori:
Na tom něco bude. Teď sice smyčka nevzniká, ale i tam určitě být nemá. Když tam dám c tak tam mám smyčku.


edit: ještě to musím prozkoumat. Vypadá to že těch výsledků $matches[0] je hodně
honky tonk
Profil *
Tori:
Ta poznámka že se to mohlo zacyklovat byla hodně dobrá. Tohle si musím zapamatovat, že smyčky tohoto druhu, které používají count je třeba pojistit proti zacyklení:

if (count($matches[0]))  // ochrana proti zacyklení ! ! !
   for( $c=0; $c<count($matches[0]); $c++):
        $matches[0][$c][0] = preg_replace("@class=\"\d{1,3}\">@", "", $matches[0][$c][0]);
   endfor;
1Pupik1989
Profil
count vrátí 0 pokud je pole prázdné. Tudíž cyklus neproběhne. Spíš bych ověřoval jestli to je pole když už. Počet prvků bych si dal zvlášť do proměnné, nemá cenu při každé iteraci zjišťovat počet prvků v poli.
Tori
Profil
honky tonk:
Do té podmínky hoďte celý preg_match_all - když nic nenajde, vrací FALSE; když najde, tak vrací počet nalezených shod - takže nepotřebujete ani count($matches[0]).


A vlastně, kdybyste ten regulár upravil na: preg_match_all("@class=\"\d{1,3}\">(\d{1,3})(?=<)@", $block, $matches, PREG_OFFSET_CAPTURE, 0);, tak pak máte všechna nalezená čísla v $matches[1] a nemusíte z nich nic odmazávat.
honky tonk
Profil *
Tori:
Nevím co by to udělalo s tou stávající strukturou:
http://paste.ofcode.org/JEDBnEvvjQeQ2cYaVYCBbW
Tori
Profil
honky tonk:
Tak pak se to dá ještě přepsat takhle:

preg_match_all('@(?<=class="\d">|class="\d\d">|class="\d\d\d">)\d{1,3}(?=<)@', $block, $matches, PREG_OFFSET_CAPTURE, 0);
Tím zůstává $matches[0] pro výsledky.
honky tonk
Profil *
Tori:
A nenapadá tě k tomuto:
preg_match_all("@(?<=style=\"display: inline\">)\d{1,3}(?=<)@", $block, $matches, PREG_OFFSET_CAPTURE, 0);

Proč mi to v kódu
<span style="display: inline">201</span>
nenajde číslo 201?
Tori
Profil
Mně to funguje.
honky tonk
Profil *
Tori:
A tenhle?
preg_match_all("@(?<=>)\d{1,3}(?=\.?)(?=<[^/])@", $block, $matches, PREG_OFFSET_CAPTURE, 0);

Měl by vyhledat číslo 176, mezi číslem a < se může vyskytnout tečka...

hledané číslo 176 v bloku:
.</span>176.<span



Testuju to tady a vrací mi to prázdné pole: http://www.functions-online.com/preg_match.html


Tak tenhle regular jsem si už opravil
"@(?<=>)\d{1,3}(?=\.?<[^/])@"


Další problém mám s tímto:

@(?<=style=\"display: inline\">)\d{1,3}(?=\.?<)@

<span style="display: inline">113</span><span class="qazL">.</span><span style="display: inline">111</span

vrací
array (
0 =>
array (
0 => '113',
1 => 30,
),
)

Ale měl by vrátit 113 a 111 . Proč nevrací 111?
honky tonk
Profil *
Vyřešeno.
honky tonk
Profil *
Dotaz
jak vyhledat čas psaný slovy který je mezi řádky (začíná na novém řádku, ale je předcházen >. ?
>
10 hours and 52 minutes</span></td>

preg_match("@(?<=>)(?s)\.{1,150}[\w ]{1,30}(?=</span></td>)@", $data, $checkMatchArr, PREG_OFFSET_CAPTURE, 0);

Zkoušel jsem výraz i bez té první části která hledá ten přechod na nový řádek a ani to moc effektivně nefuguje protože mi to našlo jen 2 minutes.


preg_match("@(?<=class=\"updatets \">)\n{1,250}[\w ]{1,30}(?=</span></td>)@", $data, $matches);

Toto mi funguje ale vrací pouze 2 minutes. Když to testuju na té testovací stránce tak to vrací komplet:
array (
0 => '
10 hours and 52 minutes',
)

Nevíte proč to nevrací celou délku?
honky tonk
Profil *
Hej, tak jsem to vyřešil. Zjistil jsem že ty data se načítají z jiného souboru, než jsem měl načtený v prohlížeči ...

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: