[php]willekeurige regel selecteren uit txt bestand

Pagina: 1
Acties:
  • 203 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Jochemmol
  • Registratie: Augustus 2004
  • Laatst online: 07-05-2014
Ik ben bezig om een script te maken waarmee ik regels uit een text bestand lees.

Nu kan ik wel alle regels uitlezen uit het bestand. Dit kan op meerdere manier via een while loop (!eof)

Ik doe het zo
PHP:
1
2
3
4
5
6
    $file=$_POST['Bestand'];
    
    $bestand = fopen($file,"r");
    while ($data = fgets($bestand, 4096)) { 
        echo $data."<p>";
    }

Nu leest hij alle regels per regel uit. Ik echo de regel en vul hem opnieuw. Nu kan ik daar wel een array van maken. Dus van alle regels. Maar wat ik mij afvraag is. Kan ik niet aangeven dat ik bijvoorbeeld dat ik alleen regel 5 of regel 100 wil hebben uit het text bestand? Ik kan op php.net niks erover vinden.

Door alles eerst in een array te zetten en dan "data[5]" op te vragen heb ik ook regel 5 (als array bij 1 begind :P )
PHP:
1
2
3
4
5
6
                $teller=1;
    $bestand = fopen($file,"r");
    while ($data[$teller] = fgets($bestand, 4096)) {    
        echo $data[$teller]."<p>";
                  $teller++;
    }

Maar als ik een record heb met 10.000 regels is dat niet practisch lijkt mij. 8)7

[ Voor 14% gewijzigd door Jochemmol op 01-12-2005 11:09 ]

Jochemmol


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Als je een random regel wilt hebben zul je eerst moeten weten hoeveel regels het bestand heeft. Als je dat wilt weten zul je toch echt eerst het hele bestand in moeten lezen lijkt mij.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Steven
  • Registratie: December 2000
  • Laatst online: 05-07 21:17
Zoiets:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
$linenr = 10;
$handle = @fopen("/tmp/inputfile.txt", "r");
if ($handle) {
   while (!feof($handle || $i < $linenr)) {
       $tmp = fgets($handle, 4096);
       if ($linenr == $i) {
              $line = $tmp;
       }
       $i++;
   }
   fclose($handle);
}
echo $line;


Als je vantevoren het aantal regels niet weet zou je op de eerste regel ook nog het aantal regels kunnen zetten.

[ Voor 20% gewijzigd door Steven op 01-12-2005 11:11 ]


Acties:
  • 0 Henk 'm!

  • mcB
  • Registratie: Mei 2002
  • Laatst online: 15-09 08:39

mcB

@Steven
$tmp is geen regel, maar een stuk van de inputfile van 4096 bytes groot.
Niet echt een goede oplossing dus

Strix (Skullflame)


Acties:
  • 0 Henk 'm!

  • Shadowman
  • Registratie: Januari 2002
  • Niet online
PHP:
1
2
3
4
$lines = file("/tmp/inputfile.txt");
$aantal_regels = count($lines);

echo $lines[rand(0, $aantalregels-1)];


edit:
ehm, sorry, topicstart niet echt goed gelezen.

Je kunt met stat wel het aantal bytes opvragen in een file en dan uitgaan van een gemiddelde lengte per regel. Kom je alleen nooit exact op regel xx uit.

[ Voor 52% gewijzigd door Shadowman op 01-12-2005 11:23 ]


Acties:
  • 0 Henk 'm!

  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 07-09 09:59
en het is wel terug te vinden op de php site :-)

http://php.belnet.be/manual/nl/function.file.php

"Live as if you were to die tomorrow. Learn as if you were to live forever"


Acties:
  • 0 Henk 'm!

  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 04-02-2022

tombo_inc

uhuh

precies, file() leest een bestand per regel in een array. en dan kun je het hele zaakje gewoon per regel aanspreken.

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Ja maar het gaat er juist om dat niet de hele file eerst ingelezen wordt. Zo kan het wel zonder de hele file eerst in te lezen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?
$filename   = "bigfile.txt";
$size       = filesize($filename);
$fp         = fopen($filename, "rb");
$pos        = rand(0, $size);
$buffer     = "";
$readsize   = 1;
fseek($fp, $pos);
while(!feof($fp) && (substr_count($buffer, "\n") < 2)) {
    $buffer.= fread($fp, $readsize);
}
$from = strpos($buffer,"\n");
$to   = strrpos($buffer,"\n");
if($from != $to) {
    $line = substr($buffer, $from, $to - $from);
}
elseif($from != null) {
    $line = substr($buffer, $from);
}
else {
    fseek($fp, 0);
    $buffer = "";
    while(substr_count($buffer, "\n") < 1) {
        $buffer.= fread($fp, $readsize);
    }
    $line = $buffer;
}

echo $line;
?>

met $readsize kun je een beetje spelen, die mag niet groter zijn dan de kortste regellengte. maar je zou die ook wel kunnen verhogen en de berekening iets anders doen.

Acties:
  • 0 Henk 'm!

  • Steven
  • Registratie: December 2000
  • Laatst online: 05-07 21:17
mcB schreef op donderdag 01 december 2005 @ 11:17:
@Steven
$tmp is geen regel, maar een stuk van de inputfile van 4096 bytes groot.
Niet echt een goede oplossing dus
Volgens mij niet:
Bron http://php.net/fgets
string fgets ( resource handle [, int length] )

Returns a string of up to length - 1 bytes read from the file pointed to by handle. Reading ends when length - 1 bytes have been read, on a newline (which is included in the return value), or on EOF (whichever comes first). If no length is specified, the length defaults to 1k, or 1024 bytes.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik zou toch iets met file() doen. Je kan nooit van te voren weten hoeveel regels er in een bestand zitten zonder het eerst te lezen ( Of het ergens op te slaan ).

dus dan kom je op
PHP:
1
2
$lines = files( $myFile );
$randLine = $lines[ rand( 0, count( $lines ) ];

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

rwb schreef op donderdag 01 december 2005 @ 12:54:
Ik zou toch iets met file() doen. Je kan nooit van te voren weten hoeveel regels er in een bestand zitten zonder het eerst te lezen ( Of het ergens op te slaan ).
Zoals Genoil laat zien hoef je dat ook niet te weten: als je een willekeurige regel nodig hebt, kan je net zo goed een willekeurige byte kiezen en dan naar de omliggende regeleindes zoeken. Dan hoef je alleen de filesize te kennen en hoef je niet alle regels te tellen. Een slim staaltje 'buiten de probleemstelling denken'.

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Confusion schreef op donderdag 01 december 2005 @ 13:01:
[...]

Zoals Genoil laat zien hoef je dat ook niet te weten: als je een willekeurige regel nodig hebt, kan je net zo goed een willekeurige byte kiezen en dan naar de omliggende regeleindes zoeken. Dan hoef je alleen de filesize te kennen en hoef je niet alle regels te tellen. Een slim staaltje 'buiten de probleemstelling denken'.
Als het niet uithaalt dat sommige regels dan meer kans hebben om gekozen te worden is dat idd een goede oplossing.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
rwb schreef op donderdag 01 december 2005 @ 12:54:
Ik zou toch iets met file() doen. Je kan nooit van te voren weten hoeveel regels er in een bestand zitten zonder het eerst te lezen ( Of het ergens op te slaan ).
Dat hoeft dus niet als je mij post had gelezen. Dit is wat mijn scriptje doet:
• leest lengte (in bytes) uit bestand
• neemt een random getal tussen 0 en de lengte
• springt naar de byte op de positoe van het random getal met fseek
• leest vanaf daar een buffer in totdat er twee linebreaks in de buffer zitten
• geeft de regel terug tussen de 2 linebreaks
• als de buffer geen regeleinden bevat neemt ie de eerste regel.

//spuit 11 ;)

[edit]
mja het is natuurlijk wel zo dat de regel na een langere regel meer kans heeft om gevonden te worden...

[ Voor 10% gewijzigd door Genoil op 01-12-2005 13:10 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Genoil schreef op donderdag 01 december 2005 @ 13:07:
[...]


Dat hoeft dus niet als je mij post had gelezen. Dit is wat mijn scriptje doet:
• leest lengte (in bytes) uit bestand
• neemt een random getal tussen 0 en de lengte
• springt naar de byte op de positoe van het random getal met fseek
• leest vanaf daar een buffer in totdat er twee linebreaks in de buffer zitten
• geeft de regel terug tussen de 2 linebreaks
• als de buffer geen regeleinden bevat neemt ie de eerste regel.

//spuit 11 ;)

[edit]
mja het is natuurlijk wel zo dat de regel na een langere regel meer kans heeft om gevonden te worden...
Ik had je post idd niet goed gelezen. Maar op die manier heeft een 2 maal zo lange regel ( eigenlijk de regel erna ;) ) ook 2 maal zoveel kans om gekozen te worden. Als dat geen probleem is dan is het idd een mooie oplossing. Het ligt er denk een beetje aan wat je precies wilt en hoe groot het bestand is wat de beste oplossing is.

[ Voor 3% gewijzigd door Woy op 01-12-2005 13:14 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 18-09 12:02

bvp

.......
Maar wat ik mij afvraag is. Kan ik niet aangeven dat ik bijvoorbeeld dat ik alleen regel 5 of regel 100 wil hebben uit het text bestand? Ik kan op php.net niks erover vinden.
....
Dat hoeft dus niet als je mij post had gelezen. Dit is wat mijn scriptje doet:

leest lengte (in bytes) uit bestand

neemt een random getal tussen 0 en de lengte
Volgens mij lezen jullie allemaal de post van de TS niet goed.
Hij heeft (volgens mij) nergens gevraagd om een random regel, maar wil zelf aangeven welke regel hij wilt hebben van het text-bestand.
Dus "buiten de probleemstelling denken" gaat hier ook niet echt goed werken ben ik bang, en zo zal er altijd de file helemaal ingelezen moeten worden...

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Denk idd dat de topicstarter dit zocht

[ Voor 5% gewijzigd door r0bert op 01-12-2005 14:00 ]


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
bvp schreef op donderdag 01 december 2005 @ 13:44:

Volgens mij lezen jullie allemaal de post van de TS niet goed.
Hij heeft (volgens mij) nergens gevraagd om een random regel, maar wil zelf aangeven welke regel hij wilt hebben van het text-bestand.
Dus "buiten de probleemstelling denken" gaat hier ook niet echt goed werken ben ik bang, en zo zal er altijd de file helemaal ingelezen moeten worden...
Je hebt idd helemaal gelijk, er staat nergens random! :D. Onderstaande is denk ik gemiddeld wel sneller dan de hele file inlezen, hangt er vanaf of je voor of achteraan in het bestand wil lezen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?
function get_lines($filename, $from, $size = 1) {
    $fp = fopen($filename, "rb");
    $current_line = 1;
    while(!feof($fp) && $current_line++ < $from) {
        fgets($fp);
    }
    if(!feof($fp)) {
        $to     = $current_line + $size;
        $lines  = array();
        while(!feof($fp) && $current_line++ < $to) {
            $lines[] = trim(fgets($fp));
        }
        return $lines;
    }
    else {
        return null;
    }
}

print_r(get_lines("bigfile.txt", 3, 3));
?>

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Genoil schreef op donderdag 01 december 2005 @ 14:22:
Je hebt idd helemaal gelijk, er staat nergens random! :D. Onderstaande is denk ik gemiddeld wel sneller dan de hele file inlezen, hangt er vanaf of je voor of achteraan in het bestand wil lezen:
Ik weet niet of ondertussen de topictitel aangepast is, maar er staat toch echt "willekeurige regel selecteren uit txt bestand". Random seeken en van daaruit de dichtsbijzonde regel eruit slopen is dan de meest performance methode.
PHP:
1
2
3
4
5
<?
while(!feof($fp) && $current_line++ < $from) {
    fgets($fp);
}
?>
Ik snap niet waarom je het zo omslachtig doet, en wat je nu eigenlijk met die code wil, maar je zoekt nog steeds vanaf het begin het hele bestand door.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Hydra schreef op donderdag 01 december 2005 @ 14:34:

Ik snap niet waarom je het zo omslachtig doet, en wat je nu eigenlijk met die code wil, maar je zoekt nog steeds vanaf het begin het hele bestand door.
Nou, in m'n eerste post had ik de fseek oplossing gegeven om een random regel eruit te krijgen. Er staat idd wel 'willekeurige regel', maar uit de startpost blijkt duidelijk dat TS een bepaalde regel wil:
...bijvoorbeeld dat ik alleen regel 5 of regel 100 wil hebben...
Dus moet je toch echt vanaf het begin regels gaan tellen, en dat doe ik met dat stukje code waarvan jij niet begrijpt wat ik er mee wil ;). Het voordeel van deze functie is dat je het bestand maar inleest t/m de regel(s) die je wilt hebben. Als je de laaste regel wilt hebben is het niet sneller dan file()..

[edit]
Ik heb nog maar even gebenchmarked met een bestand van 10000 regels en 446 karakters per regel en mijn methode is gemiddeld meer dan 2 keer zo snel als dat je altijd de hele file inleest.

[ Voor 12% gewijzigd door Genoil op 01-12-2005 15:57 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Genoil schreef op donderdag 01 december 2005 @ 15:06:
[...]
Ik heb nog maar even gebenchmarked met een bestand van 10000 regels en 446 karakters per regel en mijn methode is gemiddeld meer dan 2 keer zo snel als dat je altijd de hele file inleest.
Wat ook logisch is als je random de te lezen regel bepaald aangezien je dan gemiddeld 5000 regels in zult moeten lezen en je met file gemiddeld 10000 ( Alles dus gewoon ;) ) regels in moet lezen wat dus 2 keer zo veel is.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
rwb schreef op donderdag 01 december 2005 @ 16:49:
[...]

Wat ook logisch is als je random de te lezen regel bepaald aangezien je dan gemiddeld 5000 regels in zult moeten lezen en je met file gemiddeld 10000 ( Alles dus gewoon ;) ) regels in moet lezen wat dus 2 keer zo veel is.
Ja daar zit wel wat in ja. Maar zelfs als je steeds regel 10000 eruit wil halen, is mijn methode nog zo'n 25% sneller. Dat zal wel iets te maken hebben met geheugengebruik, want mijn functie doet niets met de regels die gelezen worden om het startpunt te vinden.

Wil je overigens echt een random regel, dan kun je beter m'n eerste stukje code gebruiken want die is gemiddeld meer dan 100 keer zo snel als m'n get_lines() (met dezelfde testfile)

[ Voor 20% gewijzigd door Genoil op 01-12-2005 17:32 ]


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Hydra schreef op donderdag 01 december 2005 @ 14:34:
Ik weet niet of ondertussen de topictitel aangepast is, maar er staat toch echt "willekeurige regel selecteren uit txt bestand".
offtopic:
Ik had het ook verkeerd begrepen, maar dit is nu precies het verschil tussen willekeurig en aselect. De goede Nederlandse vertaling voor 'random' is 'aselect', niet 'willekeurig'. De topicstarter heeft het precies goed gezegd :)

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Twee dingen die mij te binnen schieten: een index bijhouden naast je file, of zorgen dat iedere regel een vaste lengte heeft van bijvoorbeeld 255 characters zodat je de precieze locatie in je bestand kunt berekenen en de daaropvolgende 255 tekens uit kunt lezen.
Pagina: 1