preg match foreach in database (mysql, php)
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
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
}
}
?>
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
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
Haha, bbcode even hersteld. Hopelijk kun je me ook met de andere vraag helpen, ikzelf vind het maar een gek iets.
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