Regex для разделения HTML-тегов

У меня есть строка HTML, например:

<img src="http://foo"><img src="http://bar">

Каким будет шаблон регулярного выражения, чтобы разделить его на два отдельных тега img?

Ответы

Ответ 1

Насколько вы уверены, что ваша строка именно такая? Как насчет ввода:

<img alt=">"          src="http://foo"  >
<img src='http://bar' alt='<'           >

Какой язык программирования? Есть ли причина, по которой вы не используете стандартный класс HTML-анализа, чтобы справиться с этим? Регулярные выражения - только хороший подход, когда у вас есть чрезвычайно известный набор входов. Они не работают для реального HTML, только для фальсифицированных демонстраций.

Даже если вы должны использовать регулярное выражение, вы должны использовать правильную грамматическую. Это довольно легко. Я протестировал следующую программу на два миллиона веб-страниц. Он заботится о случаях, которые я излагаю выше, и еще один или два других.

#!/usr/bin/perl
use 5.10.0;
use strict;
use warnings;

my $img_rx = qr{

    # save capture in $+{TAG} variable
    (?<TAG> (?&image_tag) )

    # remainder is pure declaration
    (?(DEFINE)

        (?<image_tag>
            (?&start_tag)
            (?&might_white) 
            (?&attributes) 
            (?&might_white) 
            (?&end_tag)
        )

        (?<attributes>
            (?: 
                (?&might_white) 
                (?&one_attribute) 
            ) *
        )

        (?<one_attribute>
            \b
            (?&legal_attribute)
            (?&might_white) = (?&might_white) 
            (?:
                (?&quoted_value)
              | (?&unquoted_value)
            )
        )

        (?<legal_attribute> 
            (?: (?&required_attribute)
              | (?&optional_attribute)
              | (?&standard_attribute)
              | (?&event_attribute)
              # for LEGAL parse only, comment out next line 
              | (?&illegal_attribute)
            )
        )

        (?<illegal_attribute> \b \w+ \b )

        (?<required_attribute>
            alt
          | src
        )

        (?<optional_attribute>
            (?&permitted_attribute)
          | (?&deprecated_attribute)
        )

        # NB: The white space in string literals 
        #     below DOES NOT COUNT!   It just 
        #     there for legibility.

        (?<permitted_attribute>
            height
          | is map
          | long desc
          | use map
          | width
        )

        (?<deprecated_attribute>
             align
           | border
           | hspace
           | vspace
        )

        (?<standard_attribute>
            class
          | dir
          | id
          | style
          | title
          | xml:lang
        )

        (?<event_attribute>
            on abort
          | on click
          | on dbl click
          | on mouse down
          | on mouse out
          | on key down
          | on key press
          | on key up
        )

        (?<unquoted_value> 
            (?&unwhite_chunk) 
        )

        (?<quoted_value>
            (?<quote>   ["']      )
            (?: (?! \k<quote> ) . ) *
            \k<quote> 
        )

        (?<unwhite_chunk>   
            (?:
                # (?! [<>'"] ) 
                (?! > ) 
                \S
            ) +   
        )

        (?<might_white>     \s *   )

        (?<start_tag>  
            < (?&might_white) 
            img 
            \b       
        )

        (?<end_tag>          
            (?&html_end_tag)
          | (?&xhtml_end_tag)
        )

        (?<html_end_tag>       >  )
        (?<xhtml_end_tag>    / >  )

    )

}six;

$/ = undef;
$_ = <>;   # read all input

# strip stuff we aren't supposed to look at
s{ <!    DOCTYPE  .*?         > }{}sx; 
s{ <! \[ CDATA \[ .*?    \]\] > }{}gsx; 

s{ <script> .*?  </script> }{}gsix; 
s{ <!--     .*?        --> }{}gsx;

my $count = 0;

while (/$img_rx/g) {
    printf "Match %d at %d: %s\n", 
            ++$count, pos(), $+{TAG};
} 

Там вы идете. Ничего!

Как вы можете использовать класс HTML-parsing, учитывая, как легко HTML можно обрабатывать в регулярном выражении. ☺

Ответ 3

Это будет сделано:

<img\s+src=\"[^\"]*?\">

Или вы можете сделать это, чтобы учесть любые дополнительные атрибуты

<img\s+[^>]*?\bsrc=\"[^\"]*?\"[^>]*>

Ответ 4

<img src=\"https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?\">

Пример PHP:

$prom = '<img src="http://foo"><img src="http://bar">';

preg_match_all('|<img src=\"https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?\">|',$prom, $matches);

print_r($matches[0]);

Ответ 5

Один слегка безумный/блестящий/странный способ сделать это - разделить нa > < а затем добавьте два символа соответственно в строку после разделения.

$string = '<img src="http://foo"><img src="http://bar">';
$KimKardashian = split("><",$string);
$First = $KimKardashian[0] . '>';
$Second = '<' . $KimKardashian[1];