preg match foreach in database (mysql, php)

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Robin C

Robin C

18/05/2013 12:07:17
Quote Anchor link
Ik ben op dit moment met cURL en preg_match_all, maar ik kom er niet uit! Hopelijk kan iemand hier me ermee helpen.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php

preg_match_all("/<h2 itemprop=\"name\">(.*)<\/h2>|<span>Stand: <span itemprop=\"score\">(.*)<\/span>|<span itemprop=\"date\">(.*)<\/span>|<span class=\"str\" itemprop=\"point\">(.*) <span>/", $result, $matchname, PREG_SET_ORDER);
//print_r($matchname);
foreach($matchname as $match)  {
    $query = "INSERT INTO standen (score, name, date, point) VALUES ('$match[2]', '$match[1]', '$match[3]', '$match[4]')";
    mysql_query($query) or die('Error, insert query failed');
    // wordt in 4 verschillende rijen gezet?
// in db toevoegen

}
}

?>


Nu heb ik dus de code, en ook alles werkt. Behalve het insert into, hierbij worden 4 rijen aangemaakt dus ziet de db er zo uit:
Quote:
* (rijen) | score | name | date | point
1 2-3
2 ajax-psv
3 26 aug
4 3


(ik krijg de tabel niet helemaal goed, maar iniedergeval staat op iedere rij een nieuw item,
dus op de eerste rui staat enkel score, op de tweede de name, op de derde date en op de 4e point).

Wat doe ik verkeerd?
Gewijzigd op 18/05/2013 12:11:58 door Robin C
 
PHP hulp

PHP hulp

13/01/2025 03:28:10
 
Wouter J

Wouter J

18/05/2013 12:09:43
 
Robin C

Robin C

18/05/2013 12:12:31
Quote Anchor link
Haha, bbcode even hersteld. Hopelijk kun je me ook met de andere vraag helpen, ikzelf vind het maar een gek iets.
 
Willem vp

Willem vp

18/05/2013 23:35:47
Quote Anchor link
Sorry dat ik het zeg, maar je code is volkomen ruk. ;-)

Laten we om te beginnen je vraag beantwoorden waarom er 4 rijen worden aangemaakt.

preg_match() vindt in je input 4 matches en zet die in de array $matchname. Nu denk jij waarschijnlijk dat, omdat er vier keer een (.*) in je regex zit, elk element van $matchname een array is met de vier elementen die zijn gecaptured.

Fout. Je gebruikt in je regex namelijk alternators (de '|') en daardoor maak je er als het ware aparte regexen van. Elke capture wordt dus een apart element van $matchname.

Die alternators zorgen er overigens voor dat je regex zeer inefficiënt werkt, doordat de regex-engine veel moet backtracken.

Volgende probleem: als de input-tags in een andere volgorde worden aangeboden, komen de gematchte elementen in een andere volgorde in je match-array, en dus ook in de verkeerde volgorde in je database. Als ze steeds in dezelfde volgorde staan heb je ook de alternators niet nodig.

Verder verbaas ik me erover dat de regex uberhaupt de juiste waardes vindt, omdat je die matcht met een .* en die is greedy. Je regex matcht dus niet tot de eerstvolgende </span>, maar tot de laatste. Mogelijk staan de spans elk op een aparte regel en gaat het daardoor per ongeluk goed. In gevallen als deze moet je altijd ungreedy matchen, dus met (.*?) waarbij het vraagteken zorgt voor de kortste match.

Tot slot vraag ik me af of die laatste <span> niet een tikfoutje is en </span> moet zijn (maar ik ken je input niet, dus misschien hoort het zo). Ook de spatie die ervoor staat zou ik coderen als \s* (of \s+ als er echt een spatie moet staan).

Alles in ogenschouw nemend, zou ik het zelf compleet anders doen: ik zou 4 preg_match_all-aanroepen gebruiken. Dus bijvoorbeeld:

preg_match_all ("|<h2 itemprop=\"name\">(.*?)</h2>|", $result, $names, PREG_SET_ORDER);
preg_match_all ("|<span>Stand: <span itemprop=\"score\">(.*?)</span>|", $result, $scores, PREG_SET_ORDER);

enzovoort. De | is hier overigens geen alternator, maar een pattern delimiter. Op die manier hoef je de slashes in je regex niet te escapen.

Vervolgens kun je de gematchte arrays verwerken in een for-loop:

for ($i=0; $i<count($names); $i++)
{
// Doe iets met $names[$i], $scores[$i], $dates[$i] en $points[$i]
}

Toevoeging op 19/05/2013 00:16:26:

Overigens... om de matches wat robuuster te maken, zou ik de regexen wat minder afhankelijk maken van het aantal en de plaatsing van de attributen in de tags. Dus iets als:

preg_match_all ("|<span(?:[^>]*?)itemprop=\"score\"(?:.*?)>(.*?)</span>|", $result, $scores, PREG_SET_ORDER);

(?:[^>]*?) -> ungreedy match van alles wat geen > is. Door de ?: wordt de match niet gecaptured
(?:.*?) -> ungreedy match van alles, zonder capture
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.