Вытащить текст до определенной метки

Тема в разделе "Регулярные выражения", создана пользователем GEEPERS, 20 апр 2009.

Статус темы:
Закрыта.
Модераторы: xpert13
  1. GEEPERS

    GEEPERS

    Регистр.:
    26 янв 2008
    Сообщения:
    162
    Симпатии:
    25
    Нужно вытащить текст от начала до первого тега (тег неизвестен) и от последнего закрывающего тега (он необязательно должен быть парой первого) - до конца текста. Если текст всередине не заключен ни в какие теги, его тоже надо сграбитъ.

    Схематически можно представитъ:
    HTML:
    <body>{Текст А}<some_tag>Текст Тега</some_tag>{Текст Б}<some_tag>Текст Тега</some_tag>{Текст В}</body>
    - нужно вытащить только текст <body>: {Текст А},{Текст Б},{Текст В}.
    Еще неплохо бы было учесть теги, несодержащие закрывающего тега.
    думаю через preg_match_all вытащить:
    PHP:
    preg_match_all'$reg_exp'$body$body_partPREG_SET_ORDER );
    Помогите регулярку составить:thenks:
     
  2. RolCom

    RolCom

    Регистр.:
    12 мар 2008
    Сообщения:
    351
    Симпатии:
    108
    Если так, получается в примере должно выбрать две пустых строки. Или теги body не учитывать?
     
  3. GEEPERS

    GEEPERS

    Регистр.:
    26 янв 2008
    Сообщения:
    162
    Симпатии:
    25
    ну да, как раз из <body> то мне и нужно.

    PHP:
    $reg='~^[a-z].*?/<(/?[^\>]+)\>.*?\Z~si';
    - не работает. Что не так?
     
  4. RolCom

    RolCom

    Регистр.:
    12 мар 2008
    Сообщения:
    351
    Симпатии:
    108
    Вот:
    PHP:
    <?php
    $attrs
    ='\b(?: \s*\b\w+\s*=\s*(?:"[^"]*"|\'[^\']*\'|[^<>\s"\']+) )*+  \s*+ /?+';

    $singletag='(?:BASEFONT|BR|AREA|LINK|IMG|PARAM|HR|INPUT|COL|FRAME|ISINDEX|BASE|META)';

    $blocktag='(?:P|DL|DIV|CENTER|NOSCRIPT|NOFRAMES|BLOCKQUOTE|FORM|ISINDEX|HR|TABLE|FIELDSET|ADDRESS|UL|OL|DIR|MENU|PRE|H[1-6])';

    $re="{
    ((?:[^<>]++|.)*?)
    (?:
            <
    $singletag$attrs>
        |
            <p
    $attrs>.*?(?= <$blocktag$attrs>|$)
        |
            (<(\w+)
    $attr>
            (?:
                    [^<>]++|
                    (?-2)|
                    .
            )*?
            (?:</\g{-1}\s*>|$))
        |
            $
    )
    }six"
    ;

    $text '<body>t1<span>qwe</span>t2<i>qwe</i>t3<img>t4<p>qwe<div>asdsd</div>t5<div>qwe<div>www</div>asd</div>t6</body>';

    $text=preg_replace("{<body$attrs>(.*)</body>}six"'$1'$text);
    preg_match_all($re$text$m);

    print_r($m[1]);
     
    GEEPERS нравится это.
  5. GEEPERS

    GEEPERS

    Регистр.:
    26 янв 2008
    Сообщения:
    162
    Симпатии:
    25
    ты забыл добавить <а> в блоковые теги. Я у себя просто вставил "|А|", но не работает. Точнее, не совсем так работает.
    Вот что возвращает при поиске такого кода:

    HTML:
    this is a line of text in the body
    <p id="main">this is a paragraph whose parent <a href="#">is the body</a></p>
    <a href="http://">this is a link whose parent is the body</a> middle text in the body 
    <a href="http://w3.org">this is a second link whose parent is the body</a> 
    <p>this is a second paragraph whose parent is the body</p>
    this is more body text
    Возврат:
    HTML:
    Array
    (
        [0] => 
    this is a line of text in the body
    
        [1] => <a href="#">is the body</a></p>
    <a href="http://">this is a link whose parent is the body</a> middle text in the body 
    <a href="http://w3.org">this is a second link whose parent is the body</a> 
    
        [2] => 
    )
    - (здесь я показал теги для удобства).

    Подозреваю, что кроме |A| надо еще где-то исправить?
     
  6. RolCom

    RolCom

    Регистр.:
    12 мар 2008
    Сообщения:
    351
    Симпатии:
    108
    Не, тег <a> в блоковые добавлять не надо. Разные теги, завершающие абзац, добавил а самое очевидное - закрывающий тег - забыл добавить:)
    Код:
    $re="{
    ((?:[^<>]++|.)*?)
    (?:
            <$singletag$attrs>
        |
            <p$attrs>.*?(?: </p\s*> | (?= <$blocktag$attrs>) | $)
        |
            (<(\w+)$attr>
            (?:
                    [^<>]++|
                    (?-2)|
                    .
            )*?
            (?:</\g{-1}\s*>|$))
        |
            $
    )
    }six";
    
     
    GEEPERS нравится это.
  7. GEEPERS

    GEEPERS

    Регистр.:
    26 янв 2008
    Сообщения:
    162
    Симпатии:
    25
    все же необходимо немного дополнить твой код;), т.к. если текст окружают <а> теги, они парсятся вместе с нужным текстом. Ну тут даже я разобрался: просто добавил
    PHP:
    | <a$attrs>.*?(?: </a\s*> | (?= <$blocktag$attrs>) | $)
    P.S.: если не тяжело, добавь плз. комментарии к своему коду, или отдельно опиши детали. А то вобщем смысл понятен, а что конкретно...
    Думаю другим начинающим тоже будет полезно.:)
     
  8. RolCom

    RolCom

    Регистр.:
    12 мар 2008
    Сообщения:
    351
    Симпатии:
    108
    С комментариями:
    PHP:
    <?php
    $attrs
    ='\b(?: \s*\b\w+\s*=\s*(?:"[^"]*"|\'[^\']*\'|[^<>\s"\']+) )*+  \s*+ /?+'//кусок регулярки, совпадает с атрибутами тега, все что от его названия до '>'

    $singletag='(?:BASEFONT|BR|AREA|LINK|IMG|PARAM|HR|INPUT|COL|FRAME|ISINDEX|BASE|META)'//список одиночных тегов

    $blocktag='(?:P|DL|DIV|CENTER|NOSCRIPT|NOFRAMES|BLOCKQUOTE|FORM|ISINDEX|HR|TABLE|FIELDSET|ADDRESS|UL|OL|DIR|MENU|PRE|H[1-6])'//список блочных тегов. Используется для определения конца абзаца <p>. Например  ...<p>(...)<p>...

    $re="{
    ((?:[^<]++|.)*?) #Все, что не является тегом. Символы [^<] захватываются по максимому, символы < только если не являются частью тега. Результат сохраняется.
    (?:  #Если мы здесь, значит наткнулись на смивол <, либо пришли к концу строки. Далее список альтернатив:
            <
    $singletag$attrs>  #Одиночный тег
        |
            <p
    $attrs>.*?(?: </p\s*> | (?= <$blocktag$attrs>) | $) #тег <p>. Он заканчивается либо </p>, либо перед началом одного из тегов \$blocktag, либо в конце строки
        |
            <(\w+)
    $attr> #Любой другой тег. Название тега запоминаем. Внутри тега могут быть:
            (?:
                    [^<]++| #no comments
                    (        #Такой же тег. Вернее пара открывающий/закрывющий тег.
                    <\g{2}
    $attr>
                        (?: #Внутри может быть:
                            [^<]++| #опять no comments
                            (?-1)|  #Вложеннаая пара таких же тегов. Применяем кусок регулярки с 18 по 25 строку опять
                            . #остальное
                        )*?
                    (?:</\g{2}\s*>|$) #Завершается либо закрывающим тегом, либо в конце строки
                    )| 
                    . #остальное
            )*?
            (?:</\g{2}\s*>|$) #Завершается либо закрывающим тегом, либо в конце строки
        |
            $ #Ну и последняя альтернатива первого уровня - конец строки
    )
    }six"
    ;

    $text '<body>t1<span>qwe</span>t2<i>qwe</i>t3<img>t4<p>qwe<div>asdsd</div>t5<div>qwe<div>www<div>www<div>www</div></div></div>asd</div><ul><li>asd</ul>t6</body>';

    $text=preg_replace("{<body$attrs>(.*)</body>}six"'$1'$text); //Удаляем теги <body>, если они есть
    preg_match_all($re$text$m);

    print_r($m[1]); 
    Когда комментировал нашел ошибку. Проверь, теперь должно все работать.
     
    GEEPERS нравится это.
  9. [Гилыч]

    [Гилыч] Постоялец

    Регистр.:
    5 авг 2008
    Сообщения:
    57
    Симпатии:
    17
    по крайней мере к данному примеру данный код подходит
    PHP:
    $string '<body>{Текст А}<some_tag>Текст Тега</some_tag>{Текст Б}<some_tag>Текст Тега</some_tag>{Текст В}</body>';

    preg_match_all("/<body>(.+?)<\/body>/si"$string$match); // поиск всего в тегах body, включая сам тег
    preg_match_all("/(.+?)<[^>]*>/s"$match[0][0], $matches); // $match[1][0] - в найденом ищется любой текст, после которого есть любой тег(открывающийся или закрывающийся)
    $arr = array();
    foreach(
    $matches[0] as $matches2){
        if(!
    preg_match("/<\/[^>]*>/si"$matches2) || preg_match("/<\/body>/si"$matches2)){ // если нет закрывающегося тега или это не body - трем тег и получаем текст в чистом виде 
            
    array_push($arrpreg_replace("/<[^>]*>/si","",$matches2));
        }
    }
    print_r($arr);
     
Статус темы:
Закрыта.