# Improvement of a regular expression pattern

I created this script to take informations "at-the-moment" of this site:

Pictures of name channel
Name of channel
Pictures channel
Times
Title
Type


My script (Work):

<?php

$url="http://www.programme-tv.net/programme/toutes-les-chaines/en-ce-moment.html#Grandes%20cha%C3%AEnes";$code_page = file_get_contents($url); preg_match_all('/<div class="channelItem">(.*?)<img src="(.*?)" alt="Le programme de (.*?)" width="70" height="30">/is',$code_page, $chaines); preg_match_all('/<div class="show (.*?) at-the-moment current (.*?)">(.*?)<div class="show-infos">(.*?)<\/div>/is',$code_page, $channels);$i=0;
foreach ($channels as$channel) {
if($i==3){ for ($j=0; $j < 38;$j++) {
preg_match_all('/<span class="(.*?)"><img src="http:\/\/static.programme-tv.net\/var\/epgs\/169\/80x\/(.*?)" alt="(.*?)" width="80" \/><\/span>/', $channel[$j], $image[$j]);
}
}

if($i==4){ for ($j=0; $j < 38;$j++) {
preg_match_all('/<p class="time">(.*?)<\/p>/', $channel[$j], $time[$j]);
preg_match_all('/<p class="title">(.*?)<\/p>/', $channel[$j], $title[$j]);
preg_match_all('/<p class="type">(.*?)<\/p>/', $channel[$j], $type[$j]);
}
}
$i++; } for ($i=0; $i < 38;$i++) {
$test = strpos($chaines[2][$i],' </div>'); if($test != true){
echo 'Chaines images: <img src="'.$chaines[2][$i].'"/><br />';
echo 'Chaines: '.$chaines[3][$i].'<br />';
echo 'image : <img src="http://static.programme-tv.net/var/epgs/169/80x/'.$image[$i][2][0].'" /><br />';
echo 'Temps : '.trim($time[$i][1][0]).'<br />';
echo 'Titre : '.substr($title[$i][1][0], strpos($title[$i][1][0], '>') + 1, strrpos($title[$i][1][0], '<')).'<br />';
echo 'Type : '.$type[$i][1][0].'<br />';
echo '<hr>';
}
}
?>


I would like to improve and find a better regular expression pattern because I use 6 regular expression pattern.

• What do you mean by "pattern"? I assume you mean regular expression pattern? Additionally, you say that you're using 4 but I can see 6. – Simon Forsberg Dec 26 '14 at 13:56
• Oops yes it's 6 ^^ sorry. And yes I mean "regular expression pattern". – Pilipe Dec 26 '14 at 14:04
• Please read: What you may and may not do after receiving answers - consider asking a follow-on question. Your edits herehave been rolled back – rolfl Dec 27 '14 at 12:42

To be honest I don't think your current way of handling is 'clean'. But I would suggest you to use a HTML DOM parser. I took the liberty to google it for you and http://simplehtmldom.sourceforge.net/ seems quite what you need.

It's a PHP HTML parser, which allows you to write

// Find all element which class=foo
$ret =$html->find('.at-the-moment');


preg_match_all('/<div class="show (.*?) at-the-moment current (.*?)">(.*?)<div class="show-infos">(.*?)<\/div>/is', $code_page,$channels);


To be honest, I never used this library before, but I've worked with beautifulsoup which is a Python equivalent, which would do the trick for you perfectly. (source: http://www.givegoodweb.com/post/210/html-parser-for-php)

Wishing you the best!

• – Simon Forsberg Dec 26 '14 at 15:23
• Thank you. I try to use DOMDocument at the moment. And later your HTML DOM parser for watch the difference. In what conditions does one uses regular expressions? – Pilipe Dec 26 '14 at 15:56
• This is a hard question. Regular Expressions can do awesome things in just a blink of a second, however they are hard to maintain and to check all possible scenario's. A beter question is to ask 'when shouldn't you use them?' -> programmers.stackexchange.com/questions/113237/… As you can see 'parsing HTML with regexp' is mentioned as first ;) – DJanssens Dec 26 '14 at 16:08

### Don't parse HTML with regular expressions

First of all, don't parse HTML with regular expressions.

Second of all, don't parse HTML with regular expressions.

### Indentation

Pay attention to correct indentation, for example in this code:

foreach ($channels as$channel) {
if($i==3){ // ... } if($i==4){


The indent level if this last if statement is unexpected. It gives the impression that it's outside of the foreach loop, but no it's still inside. Be careful, this kind of thing can seriously hurt readability.

### Using an alternative pattern separator instead of ///

You could simplify many of your patterns by using a different separator instead of /, for example |:

preg_match_all('|<span class="(.*?)"><img src="http://static.programme-tv.net/var/epgs/169/80x/(.*?)" alt="(.*?)" width="80" /></span>|', $channel[$j], $image[$j]);


This way you don't need to escape so many embedded /, which is a lot easier on the eyes too.

I recommend to borrow from the formatting conventions of other languages and put spaces around operators and parentheses. Instead of this:

if($i==4){  Write like this: if ($i == 4) {


### Conditions on boolean expressions

When working with boolean values, you don't need the == or != operators, you can use the boolean values directly. Instead of this:

if($test != true){  You can write simply: if (!$test) {

• Thank you for the constructive comments and for the tips. I did not know for the patterns. I have my script properly indent but on this forum the indent have changed :( – Pilipe Dec 27 '14 at 7:47

Script with DOMDocument :

<?php

$url="http://www.programme-tv.net/programme/en-ce-moment.html#TNT%20-%20Cha%C3%AEnes%20Gratuites";$html = file_get_contents($url);$dom = new DOMDocument;
@$dom->loadHTML($html);

$classname = 'at-the-moment';$xpath = new DOMXPath($dom);$datas = $xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), '$classname ')]");

foreach ($datas as$data) {
$tags =$data->getElementsByTagName('img');
if($tags->length === 1){ foreach ($tags as $tag) {$infos['image_en_cours'][] = $tag->getAttribute('src'); } } else {$infos['image_en_cours'][] = 'no_image';
}

$xml =$data->ownerDocument->saveXML($data);$dom->loadHTML($xml);$xpath = new DOMXPath($dom);$classname = 'title';
$titles =$xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]"); foreach ($titles as $title) {$infos['titre'][] = $title->nodeValue; }$classname = 'time';
$times =$xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]"); foreach ($times as $time) {$infos['temps'][] = $time->nodeValue; }$classname = 'type';
$types =$xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]"); foreach ($types as $type) {$infos['types'][] = $type->nodeValue; } } @$dom->loadHTML($html);$xpath = new DOMXPath($dom);$classname = 'channel_logo';
$channels =$xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]"); foreach ($channels as $channel) {$datas = $channel->getElementsByTagName('img'); foreach ($datas as $data) {$infos['image_nom_television'][] = $data->getAttribute('src');$infos['nom_chaine'][] = substr($data->getAttribute('alt'), 16); } } for ($i = 0; $i < 38;$i++) {
echo 'Image de la chaine : <img src="'.$infos['image_nom_television'][$i].'" alt="'.$infos['nom_chaine'][$i].'" /><br />';
echo 'Nom de la chaine : '.$infos['nom_chaine'][$i].'<br />';
echo utf8_decode('Image en cours : <img src="'.$infos['image_en_cours'][$i].'" alt="'.$infos['titre'][$i].'" /><br />');
echo utf8_decode('Titre : '.$infos['titre'][$i].'<br />');
echo 'Commencé à : '.$infos['temps'][$i].'<br />';
echo utf8_decode('Genre : '.$infos['types'][$i].'<br />');
echo '<hr>';
}

?>


I think this script is better than the first. What do you think ? you see an optimization ?