Regex - сопоставление имен тегов только в HTML - PullRequest
1 голос
/ 25 августа 2011

Как я могу использовать регулярные выражения для получения всех имен тегов html внутри фрагмента html? Я использую PHP, чтобы сделать это, если это имеет значение. Например:

<div id="someid">
     <img src="someurl" />
     <br />
     <p>some content</p>
</div>

должен вернуть: div, img, br, p.

Ответы [ 3 ]

3 голосов
/ 25 августа 2011

Это должно работать для большинства правильно сформированных разметок, если вы не находитесь в разделе CDATA и не играли в грязные игры, переопределяя сущности:

# nasty, ugly, illegible, unmaintable — NEVER USE THIS STYLE!!!!
/<\w+(?:\s+\w+=(?:\S+|(['"])(?:(?!\1).)*?\1))*\s*\/?>/s

или более разборчиво, например

# broken out into related elements grouped by whitespace via /x
/ < \w+ (?: \s+ \w+ = (?: \S+ | (['"]) (?: (?! \1) . ) *? \1 )) * \s* \/? > /xs

и даже более разборчиво, как это:

/ 
   # start of tag, with named ident
   < \w+ 
   # now with unlimited k=v pairs 
   #    where k is \w+ 
   #      and v is either \S+ or else quoted 
   (?: \s+ \w+ = (?: \S+        # either an unquoted value, 
                   | ( ['"] )   # or else first pick either quote
                     (?: 
                        (?! \1) .  # anything that isn't our quote, including brackets
                     ) * ?     # maximal should probably work here
                     \1        # till we see it again
                 ) 
   )  *    # as many k=v pairs as we can find
   \s *    # tolerate closing whitespace

   \/ ?    # XHTML style close tag
   >       # finally done
/xs

Вы можете добавить немного помои, например, допускать пробелы в некоторых местах, где я не выше.

PHP не обязательно является лучшим языком для такой работы, хотя вы можете обойтись в крайнем случае.И самое меньшее, вы должны спрятать этот материал в функции и / или переменной где-нибудь, не оставлять его открытым как голый, учтите, что The Children Are Watching ™.

Чтобы сделать что-то более сложное, чем найти ойЯ не знаю букв или пробелов, шаблоны очень выигрывают от комментариев и пробелов.Это должно быть само собой разумеющимся, но по какой-то причине люди забывают использовать /x для когнитивного разделения, позволяя пробелу группировать связанные вещи так же, как вы делаете с императивным кодом.

Даже если они являются декларативными программами, а не императивными,Более того, шаблоны извлекают выгоду из полной декомпозиции проблем и проектирования сверху вниз. Один из способов реализовать это - это когда у вас есть "подпрограммы регулярного выражения", которые вы объявляете отдельно от места их использования.В противном случае вы просто выполняете повторное использование кода «вырезать и вставить», то есть повторное использование кода в пессимальной сортировке.Вот пример шаблона для сопоставления тега <img>, на этот раз с использованием реального Perl:

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's 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;

Да, он становится длинным, но с увеличением длины он становится более понятным, а не меньшим. Это также более правильно. Теперь настоящая программа, в которой она используется, делает не только это, потому что вам приходится учитывать гораздо больше, чем в реальном HTML, например, CDATA, кодировках и т.д.озорные переопределения сущностей.Однако, вопреки распространенному мнению, вы можете на самом деле делать такие вещи с PHP, потому что он использует PCRE, который позволяет (?(DEFINE)...) блоков и рекурсивных шаблонов.У меня есть более серьезные примеры такого рода вещей в моих ответах здесь , здесь , здесь , здесь и здесь.

Хорошо, хорошо, вы прочитали все это или хотя бы взглянули на них?Все еще со мной?Привет??Не забудьте дышать.Там, теперь ты будешь в порядке.:)

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

1 голос
/ 25 августа 2011

Регулярные выражения могут не всегда работать.Если вы на 100% уверены, что это правильно сформированный XHTML, регулярные выражения могут быть способом сделать это.Если нет, используйте какую-то библиотеку PHP, чтобы сделать это.В C # есть нечто, называемое Agility Pack HTML, http://htmlagilitypack.codeplex.com, например, см. Как мне анализировать HTML с помощью регулярных выражений в C #? .Возможно, в PHP есть эквивалентный инструмент.

1 голос
/ 25 августа 2011

Полагаю, это должно сработать ... Я попробую через минуту:

edit: удалено \s+ (спасибо Петерису)

preg_match_all('/<(\w+)[^>]*>/', $html, $matched_elements);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...