Domanda

Sto cercando di recuperare i tag specifici con il loro contenuto di un documento xhtml, ma è un abbinamento sbagliato di fine tag.

Il seguente contenuto:

<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>

Il content_block fine tag per id="benvenuto" in realtà è abbinato come la fine tag della prima apertura content_block tag.

La regex che sto usando è:

/<content_block id="(.*)">([\w\W]*?)<\/content_block>/i

Puntatori come dove sto fallendo?

È stato utile?

Soluzione

... e la risposta è sempre la stessa: HTML + espressione regolare non può essere fatto . Scusate. Utilizzare una libreria di parsing del codice HTML per il vostro quadro particolare. Oppure, se il documento è garantito per contenere solo XHTML valido, prendere l'approccio XPath come proposto da jitter in un commento.

Altri suggerimenti

questo potrebbe aiutare ho trovato tutorial su http://www.regular-expressions.info/examples.html che menziona la cattura paio di stringa ricorrenti nel testo dato. suggerimento è quello di usare? dopo. * farlo smettere dopo la prima occorrenza di finire stringa della coppia nel testo

Questo è un problema noto con regex - Non è possibile abbinare le coppie. Matching è sia avido, in cui si abbina l'ultima che trova, o non avido, in cui corrisponde il primo. Non si può convincere un regex per contare parentesi di apertura e chiusura.

mi sento di raccomandare di caricarle in un DOM e utilizzando tale. Se si sta cercando di implementare un parser HTML, mi consiglia di utilizzare espressioni regolari per lex, poi un parser sinistra-destra per analizzare l'output del lexer.

grazie a @Jan Żankowski e @ikegami, la loro risposta mi ha dato inpiration

Mi permetta di usare PHP per dimostrare il codice

<?php
$xml = <<<EOT
<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
EOT;

preg_match('/<cache_namespace[^>]+>((?:(?!(<\/?div>)).)*)<\/cache_namespace>/s', $xml, $matches);
print_r($matches);

regex nota

  • s opzione:un . nel modello corrisponde a tutti i caratteri, compresi i ritorni a capo
  • La chiave qui è che (?:(?!STRING).)* è per stringhe [^CHAR]* è caratteri

risultato

Array
(
    [0] => <cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
    [1] => 
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>

)

Analisi XHTML o XML non è difficile. Ho pensato che si dispone di codice valido o ben formato.

#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
my $xml = <<"EOF";
<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
EOF

while ($xml =~ m!
<(content_block)\sid="welcome"> # Start tag definition.
 (\s*                           # It may consists of
   (?: <\!--.*?-->              # - comment
   |  [^<]*                     # - text
   |  <[^>]+/>                  # - another closed tag
   |  <\s*(\w+)[^>]*>           # - another tag with some content
       (?2)+                    # (recursive definition of possible tag content)
      </\3>
   )
 )*
</\1>
!sxgc) {
    print "==> $&\n\n";
}

Si prega di modificare la definizione di tag di inizio per un altro contenuto (come <\s*(\w+)[^>]*+>). Comunque è un buon punto di partenza.

Se non si utilizza la ricorsione (linea con (?2)+) si bloccato su esempi . Questo codice tutti in grado di gestire (si prega di guardare qui prima) o può adattare facilmente per nuove situazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top