Авторские статьи Регулярные выражения [Beta-version]

Discussion in 'Статьи' started by Talisman, 20 Mar 2007.

  1. Talisman

    Talisman Elder - Старейшина

    Joined:
    22 Apr 2006
    Messages:
    400
    Likes Received:
    151
    Reputations:
    80
    Привет, все же эта статья не о моих мыслях, а о созданном до меня творении - регулярных выраженийх, то не буду копипастить "заводские" мануалы, а сразу перейду к делу.
    Регулярные выражения
    Как всегда, материал для затравки:
    http://molody.tagiltelecom.ru/doc/program/www/php4/ru/reference.pcre.pattern.syntax.html
    и http://www.providerz.ru/articles/php/regexp-intro.html
    прочитали? ну хотябы просмотрели? тогда едем дальше :)
    PHP
    Разберу только пшп, ибо наиболее распространен, да и в перле все точно так же)
    Функции, которые работают с регулярками:
    preg_match - http://ru2.php.net/manual/en/function.preg-match.php
    PHP:
    int preg_match(
    string pattern// регулярка
    string subject// строка, где ищем
    [, array matches// куда поместятся результаты поиска
    )
    Тамошний примерчик:
    PHP:
     <?
      function is_email($Addr) 
      {
        $p = '/^[a-z0-9!#$%&*+-=?^_`{|}~]+(\.[a-z0-9!#$%&*+-=?^_`{|}~]+)*'; // имя аккаунта
        $p.= '@([-a-z0-9]+\.)+([a-z]{2,3}'; // зоны второго уровня
        $p.= '|info|arpa|aero|coop|name|museum)$/ix'; // зоны первого уровня
        return preg_match($p, $Addr);
      }
    ?>
    preg_match_all - http://ru2.php.net/manual/en/function.preg-match-all.php -аналогична простому preg_match, только эта позволяет задать порядок, в котором выводятся результаты:
    PHP:
    int preg_match_all(
    string pattern// регулярка
    string subject// строка, где ищем
    array matches // куда поместятся результаты поиска
    [, int order// порядок размещения строк в результирующем массиве, принимает значения:
    PREG_PATERN_ORDER нулевой элемент будет массивом полных соответствий шаблону.
    PREG_SET_ORDER начиная с нулевого симовола
    )
    Как видно, эта функция просто более удобна в некоторых ситуациях.
    preg_split -http://ru2.php.net/manual/en/function.preg-split.php - разбивает строку в соответствии с регулярным выражением и возвращает массив строк, как функция split() ( http://ru2.php.net/manual/en/function.split.php ):
    PHP:
    array preg_split(
    string pattern// регулярка
    string subject// строка, которую разбиваем
    [, int limit // ограничение найденных значений
    [, int flags// если указать PREG_SPLIT_NO_EMPTY то функция вернет только не пустые строки
    )
    ereg_replace - http://ru2.php.net/manual/en/function.ereg-replace.php - обрабатывает стрчоку по шаблону, например:
    PHP:
    $hash=ereg_replace("[^0-9a-fA-F]","",$hash);
    заменит все, что не цифра и не буква: abcdefABCDEF на пустое множество, т.е. вырежет все, кроме допустимых символов в хеше)
    PHP - Иной взгляд
    Вот другой взгляд на то же, про что и я говорил :)
    http://www.providerz.ru/articles/php/regexp-continue.html
    Правила хорошего тона:
    Комментируйте свои регулярки! ведь их наверняка нужно будет комментировать/изменять, поэтому совет:
    PHP:
    $hash=ereg_replace("[^ // все кроме
    0-9 // цифры
    a-f // мелкие буквы abcdef
    A-F // большие буквы на всяк случай ABCDEF
    ]"
    ,"",$hash);
    так понятнее, ведь правда?
    Зачем?
    фильтровать передаваемые скрипту значения, "сдирать" инфу с чужого сайта, да много еще как)



    ЗЫ: не спешите баянить, если что-то не понравилось... ИБО: не решился сразу переводить те 2 начальные статьи, ибо зачем? а щас появились сомнения. можт все же перевести на ВВ-теги форума?
    че сделать с теми статьями? "переварить", откомментировав каждые регулярки?
    ибо много где регулярки используются, а из-за отстуствия простой документации много вещей непонятны :)
    ЗЫ еще в тему: http://forum.antichat.ru/thread27498-%F0%E5%E3%F3%EB%FF%F0%ED%FB%E5.html
    жду камментов)
     
    4 people like this.
  2. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
  3. Talisman

    Talisman Elder - Старейшина

    Joined:
    22 Apr 2006
    Messages:
    400
    Likes Received:
    151
    Reputations:
    80
    Элементарные действия

    Является ли строка числом, длиной до 77 цифр:

    PHP:
     if(ereg("^ // отрицание
    [0-9] // цифры
    {1,77} // квантификатор повтора предыдущего элемента (цифр) от 1 до 77 раз
    $"
    ,$string)) echo "yes"; else echo "no";
    Состоит ли строка только из букв, цифр и "_", длиной от 5 до 20 символов:
    PHP:
     if (ereg("^ //отрицание
    [a-zа-я0-9_] // цифры, буквы русские, англ (строчные), и подчеркивание
    {5,20} // повторяются не менее 5 и не более 20 раз
    $"
    ,$string)) echo "yes"; else echo "no";
    Есть ли в строке любые символы, кроме допустимых. Допустимыми считаются буквы, цифры и "_". Длину тут проверять нельзя, разве что просто дополнительным условием strlen($string). Не путайте с предыдущим примером - хоть результат и одинаковый, но метод другой, "от противного"
    PHP:
    if ( ! ereg("[^a-zа-я0-9_]",$string))
       echo 
    "нет посторонних букв (OK)";
    else
       echo 
    "есть посторонние буквы (FALSE)";
    Для регистро независимого сравнения используйте eregi().
    Есть ли в строке идущие подряд символы, не менее 3-х символов подряд (типа "абвгДДДеё", но не "ааббаабб"):

    PHP:
    if (preg_match("/(.)\\1\\1/",$string)) echo "yes"; else echo "no";
    Заменить везде в тексте СТРОКУ1 на СТРОКУ2 (задача решается без регегулярных выражений):

    PHP:
    $string=str_replace("СТРОКА1","СТРОКА2",$string);
    Заменить кривые коды перехода строки на нормальные: для этого нужно только удалить "\r". Переходы бывают нормальными (но разными!): "\n" или "\r\n". Еще бывают глюки, типа "\r\r\n".

    PHP:
    $string=str_replace("\r","",$string);
    Заменить все повторяющиеся пробелы на один. Не пытайтесь здесь применить str_replace, это хорошая функция, но не для данного примера.

    PHP:
    $string=preg_replace("/ХХ+/","Х",$string); // вместо Х поставьте пробел
    В тексте есть некоторые слова, допустим "СЛОВО" и "ЛЯЛЯЛЯ" (и т.д.), которые нужно одинаковым образом заменить на тоже самое, но с добавками. Возможно, слова отсутствуют или встречаются много раз в любом регистре. Т.е. если было "слово" или "СлОвО" (или еще как), нужно заменить это на "<b>слово</b>" или "<b>СлОвО</b>" (смотря, как было). Другими словами нужно найти перечень слов в любом регистре и вставить по краям найленных слов фиксированные строки (на "<b>" и "</b>").
    PHP:
    $string=preg_replace("/(слово1|слово2|ляляля|слово99)/si","<b>\\1</b>",$string);
    // то, что в скобках, заносится потом в \\1
    // вертикальная черта означает или :)
    // остальное вроде все понятно
    Найти текст, заключенный в какой-то тег, например <TITLE> ... </TITLE> из HTML-файла ($string - исходный текст).

    PHP:
    //точка - все кроме пробела, ну и много раз повторяется)
    if (preg_match("!<title>(.*?)</title>!si",$string,$ok))
       echo 
    "Тег найден, текст: $ok[1]";
    else
       echo 
    "Тег не найден";
    Найти текст, заключенный в какой-то тег и заменить его на другой тег, например: <TITLE> ... </TITLE> заменить аналогично на <МОЙ_ТЕГ> ... </МОЙ_ТЕГ> в HTML-файле:
    PHP:
     preg_replace("!<title>(.*?)</title>!si","<МОЙ_ТЕГ>\\1</МОЙ_ТЕГ>",$string);
     
  4. Abra

    Abra Member

    Joined:
    17 Sep 2005
    Messages:
    278
    Likes Received:
    51
    Reputations:
    29
    Даж не знаю... помоему для азов - статья слишком простая. Имхо, лучше было бы написать статью про крутые регулярки, а не про элементарные. Что-то из серии ББ кодов с хорошими фильтрами, чтоб народ учился их сам писать. Ну или там с модификатором /e.

    Еще не заметл жирную надпись в самом начале "для простого поиска/замены" используется strpos и str_replace а не регулярки!!!".=)) Многие, познав такую вещь как regexp начинают ей злоупотреблять почем зря =\

    UPD только сейчас заметил: "можт все же перевести на ВВ-теги форума?" - думаю надо. Большинство людей для других целей их и не использует. А безопасность BBкодов + там фильтрация на вложенные 2ые, и 3ые тэги - вообще сама по себе интересная тема, если осилишь :)
     
    #4 Abra, 20 Mar 2007
    Last edited: 20 Mar 2007
  5. Talisman

    Talisman Elder - Старейшина

    Joined:
    22 Apr 2006
    Messages:
    400
    Likes Received:
    151
    Reputations:
    80
    ок, щас распознавалку бб кодов распишу подробно (самописка)
    ---добавлено---
    Почемуто многие самописные сайты разрешают штмл в своей админке, уж не из-за того ли, что создателям "влом" писать распознавалку бб тегов?
    вот простейший пример:
    PHP:
    <?

    // исходное сообщение:
    // ------------------------------------------------------
       
    $str='
    Памагите, ничаво не работает! Вот пример:
    [ph       p ]
    // comment
    # comment
    phpinfo();
    [/ph        p] 
    содран с: [url]http://yandex.ru/[/url]
    ляляля ляляля 
    [b]ПОМОГИТЕ!!![/b]
    [ph      p]
    for ($i=0; $i<100; $i++) {
       ping("-f","www.ru");
    }
    [/ph     p]
    [HIDE]тут хайд))) токо что в нем написать?[/HIDE]
    <? 
       echo "<a href=http://php.spb.ru/chat/>click here!</a>";
       phpinfo();
      ?>
    '
    ;
    // ------------------------------------------------------

       // подавить предупреждения (в highlight_string есть глюки) 
       
    error_reporting(0);

       
    // функция подсвечивания одного куска текста
       
    function _my_($s,$a1,$a2) {
          if (
    $a1!="<?") { $a1="<?"$a2="?>"; }
          
    $s=str_replace("\\\"","\"",$s);
          
    ob_start();
          
    highlight_string($a1.$s.$a2);
          
    $s=ob_get_contents();
          
    ob_end_clean(); 
          return 
    $s;
       }
      
       
    // ищем в тексте все куски между <?... или [php]...
    $str=preg_replace("!(\[php\]|<\?)(.*?)(\[/php\]|\?>)!ise","_my_('\\2','\\1','\\3')",$str);
    $order  = array('[center]','[/center]','[left]','[/left]','[right]','[/right]','[b]','[/b]');
    $replace = array('<div align="center">','</div>','<div align="left">','</div>','<div align="right">','</div>','<B>','</B>');
    $str str_replace($order$replace$str);
    // хайд )
          
    if($_GET['member']==='1')
          {
          
    $str ereg_replace("\[HIDE\](.*)\[\/HIDE\]","<HR>\\1<HR>"$str);
    $str ereg_replace("\[URL\]([[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/])\[\/URL\]","<a href=\"\\1\" target=\"blank\">\\1</a>"$str);
          }else
          {
          
    $str ereg_replace("\[HIDE\](.*)\[\/HIDE\]","<HR><b>Стань мембром! или не видать тебе хайдов и линков!!!</b><HR>"$str);
    $str ereg_replace("\[URL\]([[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/])\[\/URL\]","<b>Стань мембром! или не видать тебе хайдов и линков!!!</b>"$str);
          }

       echo 
    $str;

    ?>
    тут мы использовали несколько красивых регулярок для наших бб тегов:
    PHP:
    $str ereg_replace("\[HIDE\](.*)\[\/HIDE\]","<HR>\\1<HR>"$str);
    - заменяет текст, между [HIDE] и [/HIDE] на тот же текст, но в тегах <HR>, чтобы выделить его из общей массы. (конечно, нужно юзать ксс, чтобы было читабельнее))
    PHP:
     $str ereg_replace("\[URL\]([[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/])\[\/URL\]","<a href=\"\\1\" target=\"blank\">\\1</a>"$str);
    а эта регулярка обрабатывает урл адрес. ЭТО ТОЛЬКО МОДЕЛЬ! нужно во-первых, текст, отображаемый пользователю разбивать на участки, во избежание XSS атак, да и фильтровать его :)
    Заметьте, срабатывают эти регулярки, только если if($_GET['member']==='1') - истинно (так мы упростили систему авторизации), если же это ложно, то вместо хайдов выводится:
    HTML:
    <HR><b>Стань мембром! или не видать тебе хайдов и линков!!!</b><HR>
    и вместо линков то же самое, сделано это чуть измененными регулярками:
    PHP:
          $str ereg_replace("\[HIDE\](.*)\[\/HIDE\]","<HR><b>Стань мембром! или не видать тебе хайдов и линков!!!</b><HR>"$str);
    $str ereg_replace("\[URL\]([[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/])\[\/URL\]","<b>Стань мембром! или не видать тебе хайдов и линков!!!</b>"$str);
    К тому же, мы и заменяем теги
    , на аналогичные штмл вот таким кодом:
    PHP:
     $order  = array('[center]','[/center]','[left]','[/left]','[right]','[/right]','[b]','[/b]');
    $replace = array('<div align="center">','</div>','<div align="left">','</div>','<div align="right">','</div>','<B>','</B>');
    $str str_replace($order$replace$str);
    теперь о проблемах такой схемы. заметили, что я выложил пшп код не в тегах ?
    а почему? дело в том, что вобла пользуется аналогичным алгоритмом, который я описал, ей наплевать на правильную "скобочную" последовательность! как например [p hp][p hp][/ph p][/ph p] такой код она сглотит как: [ph p][p hp][/p hp] и отдельно стоящий [/ph p]. плохо, правда? как же этого избежать? можно юзать правильно настроенные регулярки в отношении жадности, а можно пойти совсем другим алгоритмом, его я опишу лиш на словах, т.к. нормальную версию кодю уже недельку)
    суть, мы разбиваем сообщение на "части" учитывая правильные скобочные последовательности, и работаем с ними функциями, например, в теге пшп запрещены теги и т.д.
    Но, почему же вбуллетин не использует это? да потому, что тогда полетит к черту вся система плагиноВ, точнее она не полетит, ее можно будет сделать, но уже только с помощью графов (более простого метода мне в голову пока не лезет :( ). а так каждый модуль, как например тег "оффтом" на аллчитс добавляет еще 1 регулярку.
    Тема очень обширная, поэтому если есть вопросы, пишите)
    да и от предложений тоже не откажусь))))
    ЗЫ проблему с
    PHP:
     решилпросто пробелов понавставлял)))
     
    #5 Talisman, 20 Mar 2007
    Last edited: 20 Mar 2007
    1 person likes this.
  6. mR_LiNK[deface_0nl

    mR_LiNK[deface_0nl Elder - Старейшина

    Joined:
    12 Dec 2006
    Messages:
    147
    Likes Received:
    27
    Reputations:
    13
    согласен, также основа - explode(); imdplode();
    )вот те статья - продвинутые реги http://www.intuit.ru/department/pl/plphp/class/free/13/5.html(мало, но тонкость, что приятно /сумеешь обмозговать и передать простым языком и со смешанными примерами - цены тебе не будет))

    имхо, не вижу смысла описывать реги, и писать целую статью на тему. Материала уйма, и не так сложно найти понятное изложение.. ну да ладно, теперь на вопры по регам буду ссылку давать..
    зы: репу зарабатываешь))
     
    #6 mR_LiNK[deface_0nl, 20 Mar 2007
    Last edited: 20 Mar 2007
    1 person likes this.
  7. Talisman

    Talisman Elder - Старейшина

    Joined:
    22 Apr 2006
    Messages:
    400
    Likes Received:
    151
    Reputations:
    80
    в конце статьи я и спросил про целесообразность :)

    про репу: есть более простые методы, чем про регулярки рассказывать) если хочешь, покажу )))
     
  8. Talisman

    Talisman Elder - Старейшина

    Joined:
    22 Apr 2006
    Messages:
    400
    Likes Received:
    151
    Reputations:
    80
    да, забыл, спасибо за линк)
    тогда уж получится хорошая подборка линков на мануалы)
     
  9. Abra

    Abra Member

    Joined:
    17 Sep 2005
    Messages:
    278
    Likes Received:
    51
    Reputations:
    29
    Угу, есть. Так что не думаю что автор за ней гоняется, имхо )

    Talisman я там один пост выше апдейтил, может ты не заметил. Не рискнешь сделать статью про безопасные ББ коды? Т.е. показать как делать ББкоды максимально устойчивые к КСС (с хорошей фильтрацией вложенных тегов). Это конечно труд непосильный, тут тебе действительно цены не будет. Я бы даже присоединился/присоединюсь к разработке, если в армию не заберут в ближайшие два месяца ))) Сам давно этим вопросом занимаюсь. Конечно всегда есть ризон выдернуть класс для обработки ббкодов из того же vbulletin'a, но все таки желание изобрести велосипед так и прет в этом вопросе =\\

    ЗЫ целесообразность в вопросе регулярок есть всегда, главное правильно это дело представить. Эта статья (фактически ликбез) все таки немного не то. Как сделать "то", не спрашивай ))