За последние 24 часа нас посетили 18117 программистов и 1590 роботов. Сейчас ищут 1262 программиста ...

Исключение строки из регулярного выражения

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

  1. sergej_savelev

    sergej_savelev Активный пользователь

    С нами с:
    10 янв 2013
    Сообщения:
    18
    Симпатии:
    1
    Здравствуйте.

    Код (PHP):
    1. $h1 = substr_count($content, '<h1');
    2.  
    3. $c = 0;
    4.  
    5. while ( $c < $h1 ) {
    6.  
    7.     $content = preg_replace(
    8.         '/<h1(.*|)>(.*[^<a name].*)<\/h1>/', 
    9.         '<h1$1>$2<a name="h1-'.$c.'"></a></h1>', 
    10.         $content, 
    11.         1 
    12.     );
    13.  
    14.     $c++;
    15.  
    16. } 
    Необходимо, чтобы во все теги h1, в переменной $content, добавлялись теги a с параметрами name со значениями, определёнными в цикле. Из вышеприведённого кода, думаю, не составит труда понять что мне нужно.

    Должно происходить следующее:
    Код (Text):
    1. <h1>Задача<h1>
    Должно заменяться на:
    Код (Text):
    1. <h1>Задача
    2.     <a name="h1-0"></a>
    3. </h1>
    После чего, в этом же выполнении, должно заменяться:
    Код (Text):
    1. <h1>Решение</h1>
    На
    Код (Text):
    1. <h1>Решение
    2.     <a name="h1-1"></a>
    3. </h1>
    Но происходит:
    Код (Text):
    1. <h1>Задача</h1>
    2. <h1>Решение</h1>
    Заменяется на:
    Код (Text):
    1. <h1>Задача
    2.     <a name="h1-0"></a>
    3.     <a name="h1-1"></a>
    4. </h1>
    5. <h1>Решение</h1>
    Подскажите, пожалуйста, как решить эту задачу? Чтобы на выходе получилось:
    Код (Text):
    1. <h1>Задача
    2.     <a name="h1-0"></a>
    3. </h1>
    4. <h1>Решение
    5.     <a name="h1-1"></a>
    6. </h1>
     
  2. sergej_savelev

    sergej_savelev Активный пользователь

    С нами с:
    10 янв 2013
    Сообщения:
    18
    Симпатии:
    1
    Убрал из цикла:
    Код (PHP):
    1. $content= preg_replace(
    2.     '/<h1(.*|)>(.*)<\/*h1>/', 
    3.     '<h1$1>$2<a name="h1-0"></a></h1>', 
    4.     $content, 
    5.     1 
    6. );
    7.  
    8. $content= preg_replace(
    9.     '/<h1(.*|)>(.*)[^<a].*<\/h1>/', 
    10.     '<h1$1>$2<a name="h1-1"></a></h1>', 
    11.     $content, 
    12.     1 
    13. ); 
    Не получается. Нужно научиться пользоваться регулярными выражениями, очевидно.
     
  3. wolfram

    wolfram Активный пользователь

    С нами с:
    11 янв 2013
    Сообщения:
    3
    Симпатии:
    0
    Код (PHP):
    1. $content='
    2. <h1>Задача</h1>
    3. <h1>Решение</h1>';
    4.  
    5. $h1 = substr_count($content, '<h1');
    6. $c = 0;
    7. while ( $c < $h1 ) {
    8.     $content = preg_replace(
    9.         '/(<h1[^>]*>[^<]*)(<\/h1>)/i',
    10.         '$1<a name="h1-'.$c.'"></a>$2',
    11.         $content, 
    12.         1
    13.     );
    14.     $c++;
    15. }
    или так
    Код (PHP):
    1. $content='
    2. <h1>Задача</h1>
    3. <h1>Решение</h1>';
    4.  
    5. function h_replace_cb($str) {
    6.     static $i = -1;
    7.     ++$i;
    8.     return $str[1] . '<a name="h1-' . $i . '"></a>' . $str[2];
    9. }
    10.     '/(<h1[^>]*>[^<]*)(<\/h1>)/i',
    11.     "h_replace_cb",
    12.     $content
    13. );
     
  4. sergej_savelev

    sergej_savelev Активный пользователь

    С нами с:
    10 янв 2013
    Сообщения:
    18
    Симпатии:
    1
    Спасибо! Второй пример ещё не смог осилить, пока первого достаточно, но, скорей всего preg_replace_callback как раз то что надо.

    Меня интересует исключение конкретно [^a\sname], чтобы обходить форматирование текста в заголовках, например:
    Код (Text):
    1. <h1 style="text-align:center;"><span style="font-weight: bold">Задача</span></h1>
    Но исключение такого рода не срабатывает.

    В случае <h1 style="text-align:center;"> Ваше wolfram решение справляется, для меня удивительно.
     
  5. wolfram

    wolfram Активный пользователь

    С нами с:
    11 янв 2013
    Сообщения:
    3
    Симпатии:
    0
    Еще как вариант
    Код (PHP):
    1. $content='
    2. <h1 style="text-align:center;"><span style="font-weight: bold">Задача</span></h1>
    3. <h1>Решение</h1>';
    4. function h_replace_cb($str) {
    5.     static $i = -1;
    6.     ++$i;
    7.     return $str[1] . $str[2] . '<a name="h1-' . $i . '"></a>' . $str[3];
    8. }
    9.     '/(<h1.*>)(.*)(<\/h1>)/i',
    10.     "h_replace_cb",
    11.     $content
    12. ); 
    должно работать
     
  6. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    можно чуть упростить
    Код (PHP):
    1. function h_replace_cb($str) {
    2.     static $i = 0;
    3.     return '<a name="h1-' . $i++ . '"></a>' . $str[0];
    4. }
    5. echo preg_replace_callback('/<\/h1>/i', 'h_replace_cb',  $content); 
     
  7. sergej_savelev

    sergej_savelev Активный пользователь

    С нами с:
    10 янв 2013
    Сообщения:
    18
    Симпатии:
    1
    Код (Text):
    1. <h1><span style="font-weight: bold">Задача</span>
    2.     <a name="h1-0"></a>
    3.     <a name="h1-1"></a>
    4. </h1>
    5. <h1>Решение</h1>
    Если будет
    Код (Text):
    1. $content='
    2. <h1><span style="font-weight: bold">Задача</span></h1>
    3. <h1>Решение</h1>';
    Вообще ничего не произойдёт, я почему и удивился что [^<]* хорошо заменяет (?:.*|).
     
  8. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    а зачем вообще привязываться к открывающему тегу <h1>
    если вам нужно просто дописать перед закрывающим.
     
  9. wolfram

    wolfram Активный пользователь

    С нами с:
    11 янв 2013
    Сообщения:
    3
    Симпатии:
    0
    Вариант предложенный runcore подходит лучше всего
     
  10. sergej_savelev

    sergej_savelev Активный пользователь

    С нами с:
    10 янв 2013
    Сообщения:
    18
    Симпатии:
    1
    Действительно. Не заметил.

    Задача с нерабочим исключением [^a>] не решена. Работает лишь '/[^>]<\/h1>/i', почему не срабатывает '/[^a>]<\/h1>/i' ?