2010-10-19 38 views
0

J'ai quelques HTML qui ressemble à ceci:teneur en extrait de chaque premier TD dans un tableau

<tr class="row-even"> 
    <td align="center">abcde</td> 
    <td align="center"><a href="deluserconfirm.html?user=abcde"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td> 
</tr> 
<tr class="row-odd"> 
    <td align="center">efgh</td> 
    <td align="center"><a href="deluserconfirm.html?user=efgh"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td> 
</tr> 
<tr class="row-even"> 
    <td align="center">ijkl</td> 
    <td align="center"><a href="deluserconfirm.html?user=ijkl"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td> 
</tr> 

Et je dois récupérer les valeurs, abcde, efgh et ijkl

C'est l'expression régulière que j'utilise actuellement:

preg_match_all('/(<tr class="row-even">|<tr class="row-odd">)<td align="center">(.*)<\/td><\/tr>/xs', $html, $matches); 

Oui, je ne suis pas très bon avec eux. Comme avec la plupart de mes tentatives de regex, cela ne fonctionne pas. Quelqu'un peut-il me dire pourquoi?

En outre, je connais les analyseurs html/xml, mais cela nécessiterait une révision de code significative pour que cela se produise. Donc c'est pour plus tard. Nous devons rester avec regex pour l'instant.

EDIT: Pour clarifier les choses, je dois les valeurs entre la première balise <td align="center"></td> après soit <tr class="row-even"> ou <tr class="row-odd">

+0

Je ne suis pas très doué avec l'expression régulière, mais est-ce qu'il vous manque une portion pour le saut de ligne entre ' JohnoBoy

+0

s'il vous plaît dites-nous ce que vous voulez faire exactement? quelle est la fonction de ceci? – klox

+0

@JohnoBoy: Comment entrer les sauts de ligne? @klox: J'ai besoin des valeurs entre la première balise – HyderA

Répondre

2
~<tr class="row-(even|odd)">\s*<td align="center">(.*?)</td>~m 

Notez que le modificateur m et l'utilisation de \s*.

Vous pouvez également rendre le premier groupe non-capturant via ?:. À savoir, (?:even|odd) que vous n'êtes probablement pas intéressé par le class attribut :)

+0

Enfin! Quelqu'un ne se disputant pas sur les analyseurs html regex v/s! Je l'ai essayé et ça fonctionne parfaitement. Juste quelques précisions s'il vous plaît, j'ai essayé le \ s avant et cela n'a pas fonctionné avec le *. Pourquoi le * est-il nécessaire? Aussi, que font les ~ caractères? – HyderA

+0

En PHP, vous pouvez utiliser n'importe quel caractère pour marquer le début et la fin de votre regex. Il a choisi '~' pour plus de commodité. Le '*' est un quantificateur. Vous l'utilisez pour dire que vous voulez entre 0 et l'infini d'une certaine classe. '\ s' dans votre cas, ce qui signifie des caractères d'espace. –

+0

@gAMBOOKa Ce que @Alin Purcaru a dit :) Le '~' est choisi car il n'est pas utilisé ailleurs dans mon modèle. Vous voyez souvent '/' utilisé comme délimiteur mais cela me forcerait à l'échapper '\ /' dans la partie ''. En ce qui concerne '\ s': il va correspondre à un espace, une tabulation ou un saut de ligne (zéro à plusieurs). – jensgram

0

Ceci est juste un regex rapide et sale pour répondre à vos besoins. Il pourrait facilement être nettoyé et optimisé, mais c'est un début.

<tr[^>]+>[^\n]*\n    #Match the opening <tr> tag 
    \s*<td[^>]+>([^<]+)[^\n]+\n #Group the wanted data 
    [^\n]+\n      #Match next line 
</tr>       #Match closing tag 

Voici une autre façon, qui peut être plus robuste:

deluserconfirm.html\?user=([^"]+) 
0

C'est ce que je suis venu avec

<td align="center">([^<]+)</td> 

Je vais vous expliquer. L'un des défis ici est de savoir ce que les tags peuvent être soit le texte que vous recherchez, soit un tag. Dans la regex le [^ <] + dit de faire correspondre un ou plusieurs caractères que n'est pas le caractère <. C'est génial, car cela signifie que le groupe ne correspondra pas, et le groupe ne correspondra que jusqu'à ce que le tag soit trouvé.

+0

J'ai juste remarqué que dans ma réponse mes marques d'ancre ont été enlevées. – mellowsoon

2

Essayez ceci:

preg_match_all('/(?:<tr class="row-even">|<tr class="row-odd">).<td align="center">(.*?)<\/td>/s', $html, $matches); 

Modifications apportées:

  • Vous avez pas absorbé la nouvelle ligne entre les balises
  • Vous n'avez pas besoin de x comme modificateur sera rejeter l'espace dans l'expression rationnelle.
  • Faire le correspondant non-gourmand en utilisant .*? à la place de .*.

Working link

+0

Merci d'avoir signalé mes erreurs exactes. Ça m'aide à apprendre! – HyderA

0

Avertissement: L'utilisation des expressions rationnelles pour analyser HTML est dangereux.

Pour obtenir le innerHTML du premier TD dans chaque TR, utilisez cette expression rationnelle:

/<tr[^>]*>\s*<td[^>]>(.+?)<\/td>/si 
2

En fait, vous ne avez pas besoin d'un changement trop grand dans votre base de code. Récupérer des nœuds de texte est toujours le même avec DOM et XPath. Tout ce qui change est le XPath, donc vous pouvez envelopper le code DOM dans une fonction qui remplace votre preg_match_all. Ce ne serait qu'un minuscule changement, par ex.

include_once "dom.php"; 
$matches = dom_match_all('//tr/td[1]', $html); 

où dom.php contient juste:

// dom.php 
function dom_match_all($query, $html, array $matches = array()) { 
    $dom = new DOMDocument; 
    libxml_use_internal_errors(TRUE); 
    $dom->loadHTML($html); 
    libxml_clear_errors(); 
    $xPath = new DOMXPath($dom); 
    foreach($xPath->query($query) as $node) { 
     $matches[] = $node->nodeValue; 
    } 
    return $matches; 
} 

et retournerait

Array 
(
    [0] => abcde 
    [1] => efgh 
    [2] => ijkl 
) 

Mais si vous voulez un Regex, utilisez une expression régulière. Je ne fais que donner des idées.

+0

J'apprécie votre effort, et c'est une réponse valable sauf que c'est beaucoup plus compliqué dans mon cas. Je prévois d'utiliser la bibliothèque simplehtmldom, que j'ai trouvée assez jolie. Cette application est pour toutes les raisons pratiques, un robot. Donc, il y a des tonnes de regex étalées sur toute l'application. Inclure simplement une nouvelle bibliothèque est un effort car il n'y a pas de classe d'inclusion de bibliothèque centrale. Je vais avoir plusieurs copies de code dans le code si je réutilise l'architecture actuelle. Mais je vois votre point de vue, et je suis sûr que cela aidera quelqu'un qui cherche une solution similaire. – HyderA

+0

@gAMBOOKa pas de problème. Vous pouvez également être intéressé par [Meilleures méthodes pour analyser HTML] (http://stackoverflow.com/questions/3577641/best-methods-to-parse-html/3577662#3577662). IMO il y a de meilleures bibliothèques que SimpleHTMLDom. – Gordon