ФорумПрограммированиеПыхнуть хотите?F.A.Q. → Регулярные выражения для пыхтящих.

Регулярные выражения для пыхтящих.

  • welder

    Сообщения: 2945 Репутация: N Группа: в ухо

    Spritz 18 июля 2007 г. 9:02

    [size=20pt]Регулярные выражения для пыхтящих.[/size]





    Регулярные выражения — это очень мощное средство для обработки ваших данных.

    Если вам требуется замена или поиск текста по шаблону , то без регулярных выражений уже не обойтись. Синтаксис регулярных выражений является относительно сложным и при его изучении нужно не мало попыхтеть. ;)

    Давайте для начала разберем простенький шаблон который ищет содержимое заголовков


    [size=15pt]#<(h1|h2|h3)>(.*)</\\1>#Uis[/size]


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


    [size=15pt]Основы регулярных выражений[/size]



    [size=12pt]1. Ограничитель шаблона[/size]

    В нашем случае символ "#" - является ограничителем шаблона им может служить любой не алфавитно-цифровой символ, кроме обратного слеша "\". Очень часто в качестве ограничителя используется "/","|","%","$" или как в моём случае "#". Если в шаблоне нужно использовать символ который у нас выбран в качестве ограничителя перед ним добавляется обратный слеш "\" (пример: "#<b>\#</b>#i")


    [size=12pt]2. Шаблон[/size]

    Шаблон это то что находится между ограничителей у нас это "<(h1|h2|h3)>(.*)</\\1>"
    в нашем шаблоне так же имеются под-шаблоны: "(h1|h2|h3)" который ищет совпадение с h1 или h2 или h3, и "(.*)" который ищет совпадение между заголовков
    и также у нас есть обратная ссылка \\1 о которой будет рассказано в пункте 4

    Давай рассмотрим синтаксис шаблонов, именно в нём и состоит вся мощь регулярных выражений:

    | - Означает логическое или.
    #а|о#
    такой шаблон ищет "a", если не найдет, будет искать "о".
    совпадет - "любитель пива" (нашлось 'а')
    совпадет - "люблю пиво" (нашлось 'о')
    не совпадет - "пиву нет!!"


    ˆ - этот знак в шаблоне обозначает, чтобы в начале обязательно стояли следующие за ним символы.

    #ˆп#

    такой шаблон ищет "п" и найдет, если он стоит первым:
    не совпадет - "водка непутинка" (нет 'п' в начале)
    совпадет - "путинка водка" ('п' в начале)

    $ - этот знак в шаблоне обозначает , чтобы в конце обязательно стояли, предшествующие ему символы.

    #т$#

    такой шаблон ищет "т" и найдет, если он стоит последним:
    не совпадет - "водка плохо" (нет 'т' в конце, нельзя)
    совпадет - "пива нет" ('т' в конце)

    . - точка в шаблоне обозначает, что шаблон совпадет с любым символ строки, кроме [\n].

    #.#

    то есть, этот шаблон совпадет с любыми символами, кроме знака [\n]:
    совпадет - "абв" (выведет только 'а' 'б' 'в')
    совпадет - "а\nб\nв" (выведет только 'а' 'б' 'в', [\n] не выведет)


    * - этот знак в шаблоне обозначает количество совпадений, это числитель ноль или более раз


    #а*#

    такой шаблон ищет "а" и найдет только в том случае, если "а" будет находиться в строке ноль или более раз. То есть, совпадет с любой строкой и вернет ее:
    совпадет - "пива нет" (есть 'а')
    совпадет - "спирт хорошо" (нет 'а', но все - равно совпадает)

    + - этот знак в шаблоне обозначает количество совпадений, это числитель 1 или более раз

    #п+#

    такой шаблон ищет "п" и найдет, если "п" будет находиться 1 или более раз.
    То есть, если "п" нет, то совпадения не будет. Если будет хотя бы одна "п", или много "п", то будет совпадение:
    совпадет - "пиво пьют" (есть 'п' один и более раз)
    не совпадет - "водку жрут" (нет 'п')

    ? - этот знак в шаблоне обозначает количество совпадений, это числитель 0 или 1 раз

    #п?#

    такой шаблон ищет "п" и найдет только в том случае, если "п" будет находиться 0 или 1 раз. То есть, если "п" не будет больше одной:
    не совпадет - "пиво пьют" (есть 'п', но больше 1 раза)
    совпадет - "пива нет" (есть 'п' один раз)
    совпадет - "водка есть" (нет 'п', но все - равно совпадет)

    { } - эти знаки в шаблоне обозначают сколько раз должно быть совпадение

    ? тоже самое, что и {0,1} - ноль или один раз
    * тоже самое, что и {0, } - ноль или более раз
    + тоже самое, что и {1, } - один или более раз
    То есть, {2,3} - должно быть два или три совпадения. Ставится после символа, который будем искать без пробелов и через запятую: {1,9} {0,35}, итд. Первая цифра обозначает минимум совпадений, последняя - максимум.

    #пиво{2,3}# - 'пиво' должно быть два или три раза
    #водка{1,2}#- 'водка' должно быть один или два раза


    \ - обратный слеш в шаблоне обозначает подстановку.
    #\.# - мы предварили точку обратным слешем и, теперь, наш шаблон будет искать точку, и совпадет только с ней в нашем тексте, а не со всеми символами, как было в последнем примере. То есть, обратный слеш служит для обозначения самих метасимволов, как обычных символов текста. Так же, все метасимволы надо предварять слешем для обозначения самих себя.

    Подстановка метасимвола:
    \\ \. \| \( \) \[ \] \{ \} \? \* \+ \ˆ \/ \# \!
    Подстановка класса символов
    \d - любой цифровой символ [0-9]
    \D - любой НЕ цифровой символ [Ր-9]
    \s - любой пробельный символ [\t\ \r\f\n]
    \S - любой НЕ пробельный символ [ˆ\t\ \r\f\n]
    \w - любой алфавитно-цифровой символ [a-zA-Z0-9_]
    \W - любой НЕ алфавитно-цифровой символ [ˆa-zA-Z0-9]

    Кроме этого, классы символов можно обозначать так:
    [[:alnum:]] - все алфавитно-цифровые символы [a-zA-Z0-9]
    [[:alpha:]] - все алфавитные символы [a-zA-Z]
    [[:blank:]] - символ табуляции и пробел [\t ]
    [[:cntrl:]] - все управляющие символы
    [[:digit:]] - все десятичные цифры [0-9]
    [[:graph:]] - все печатные символы, за исключением пробела
    [[:lower:]] - все строчные буквы [a-z]
    [[:upper:]] - все прописные буквы [A-Z]
    [[:print:]] - все печатные символы
    [[:punct:]] - все знаки препинания [\.,;:-]
    [[:space:]] - все пустые символы
    [[:xdigit:]] - все шестнадцатиричные цифры

    Если вы поставите [ˆ[:alnum:]] - любой НЕ алфавитно-цифровой символ, то есть это полная противоположность [[:alnum:]]. То есть, любой класс вы можете инвертировать посредством 'ˆ'.

    Подстановка претензий
    \b - на границе слова
    \B - не на границе слова
    \A - в начале строки
    \Z - в конце строки
    \z - в конце текста


    [size=12pt]3. Подшаблон[/size]


    ( ) - эти знаки в шаблоне обозначают ограничители подшаблона, которые можно создавать и в дальнейшем ссылаться на них. Синтаксис подшаблона тот же самый что и у самого шаблона

    в нашем шаблоне два подшаблона: "(h1|h2|h3)" который ищет совпадение с h1 или h2 или h3, и "(.*)" который ищет совпадение между заголовков


    [size=12pt]4. Обратная ссылка[/size]

    Это ссылка на подшаблон в нашем случае //1 мы обращаемся к первому подшаблону в самом шаблоне.То есть выражение "#<(h1|h2|h3)>(.*)</\\1>#Ui" равно "#<(h1|h2|h3)>(.*)</(h1|h2|h3)>#Ui"



    [size=12pt]5. Модификаторы[/size]


    Функционирование регулярных выражений можно видоизменить используя модификаторы их значение и использование описано ниже.

    i - игнорировать регистр
    #шаблон#i
    будет искать шаблон, игнорируя регистр в тексте поиска.

    s - метасимвол '.' соответствует и символу [\n], то есть классу [\0-\xFF]
    #шаблон#s
    будет искать шаблон, где '.' Игнорирует видит [\n], то есть метасимвол точка будет так же возвращать и перевод каретки на новую строку.

    U - минимизировать числитель, то есть искать как можно меньше совпадений
    #шаблон#U
    будет искать шаблон, с как можно меньшим совпадением раз. Если мы ставили в шаблоне #a?# - действие этого модификатора примерно такое же, как и минимизатора '?' в самом шаблоне.

    m - претензии 'ˆ' и '$' учитывают [\n]
    #шаблон#m
    если в шаблоне будут метасимволы 'ˆ' и '$', то претензия 'ˆ' будет искать совпадение в начале строки, а претензия '$' будет искать совпадение в конце строки.
    #ˆпиво$#m
    совапдение - "пиво\n" (в строке 'пиво')
    нет совапдения - "пи\nво" (здесь 'пиво' в разных строках)

    D - претензия '$' не учитывает [\n]
    #шаблон#D
    если в шаблоне есть метасимвол '$'.
    Претензия '$' будет искать совпадение в фактическом конце текста, игнорируя переводы каретки на новую строку [\n].

    A - привязать шаблон к началу текста
    #шаблон#A
    Будет искать шаблон только в фактическом начале теста.

    x - разрешить комментарии: пробел и #
    #шаблон#x
    здесь в шаблоне разрешены пробел и #, как комментарии, поэтому пробел и # надо предварять слешем, если только они не обозначают комментарии.
    /слово
    #комментарий
    ищу/x
    будет искать 'словоищу'. То есть, здесь игнорируются пробелы и все, что следует за знаком диез.

    X - воспринимать неверную подстановку как ошибку.
    #шаблон#X

    S - предварительная оптимизация шаблона
    #шаблон#S

    e - используется в функции 'preg_replace' для ее активации
    #шаблон#e

    тоесть в нашем случае это Ui (ищем как можно меньше совпадений, игнорируя регистр)




    [size=15pt]Основы регулярных выражений[/size]




    [size=12pt]1. в стиле POSIX[/size]


    ereg() - совпадение с регулярным выражением.

    bool ereg(string pattern, string string [, array regs])

    Данная функция ищет в строке string соответствие регулярному выражению, заданному в шаблоне pattern. Если соответствия подвыражений с шаблоном будут найдены, то они сохраняются в массиве соответствий regs. При этом $regs[0] содержит копию строки string, $regs[1] содержит подстроку, начинающуюся с первой левой скобки, $regs[2] хранит подстроку, начинающуюся со второй левой скобки и т.д.

    Ниже приведен код, преобразующий фразу "Вася любит пиво больше чем Иван" в более лучшую для меня "Иван любит пиво больше чем Вася".

    пример:


    <?php

    $text = "Вася любит пиво больше чем Иван";

    if (ereg ("(Вася) (любит пиво больше чем) (Иван)", $text, $regs)):
    echo "{$regs[3]} {$regs[2]} {$regs[1]}";
    else:
    echo "Алкоголики не найдены";
    endif;
    ?>



    Этот пример даст:

    Иван любит пиво больше чем Вася


    ereg_replace() - замещает регулярное выражение..

    string ereg_replace(string pattern, string replacement, string string)


    Эта функция заменяет найденный в строке string шаблон pattern на строку replacement и, если соответствие было найдено, возвращает модифицированную строку.

    пример:

    <?php
    $text = "Вася любит пиво больше чем Иван";
    echo ereg_replace("пиво", "водку", $text);
    ?>


    Этот пример даст:
    Вася любит водку больше чем Иван




    split() - делает из строки массив с помощью регулярного выражения.

    array split (string pattern, string string [, int limit])


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

    Эта функция полезна при разделении дат, доменных имен и т.д.

    пример:

    <?php
    $text = "пиво.дефки.рок";
    $array = split ("\.", $text);
    print_r($array);
    ?>



    Этот пример даст:
    Array ( [ О ] => пиво [1] => дефки [2] => рок )



    [size=12pt]2. Perl-совместимые регулярные выражения[/size]



    preg_match() - выполняет подстановку регулярного выражения.

    int preg_match (string pattern, string subject [, array matches])


    Эта функция ищет в строке subject соответствие регулярному выражению pattern. Если задан необязательный параметр matches, то результаты поиска помещаются в массив

    пример:

    <?php
    $str = "Вася любит пиво и Иван любит пиво";

    // пиво есть
    if (preg_match ("#пиво#i", $str)):
    echo("слово пиво втречается");
    else:
    echo("слово пиво не втречается");
    endif;

    // водки нет
    if (preg_match ("#водка#i", $str)):
    echo("слово водка втречается");
    else:
    echo("слово водка не втречается");
    endif;

    ?>



    Этот пример даст:
    слово пиво втречаетсяслово водка не втречается


    с добавлением необязательного параметра matches

    пример:

    <?php
    $url = "http://www.phpforum.ru";
    preg_match("/^(http:\/\/)?([^\/]+)/i", $url, $matches);
    print_r($matches);
    ?>



    Этот пример даст:
    Array ( [ O ] => http://www.phpforum.ru [1] => http:// [2] => www.phpforum.ru )




    preg_match_all() - выполняет глобальный поиск совпадения регулярного выражения.

    int preg_match_all (string pattern, string subject, array matches [, int flags])

    Ищет в subject все совпадения с регулярным выражением pattern и помещает их в matches в порядке, специфицированном в order.

    После нахождения первого совпадения последующий поиск продолжается до нахождения последнего совпадения.

    пример:

    <?php
    $text = "<b>Вася</b> любит <b>пиво</b> больше чем <b>Иван</b>";
    preg_match_all ("#<b>(.*)</b>#iU", $text, $regs);
    echo "<pre>";
    print_r($regs[1]);
    ?>


    Этот пример даст:
    Array
    (
    [О] => Вася
    [1] => пиво
    [2] => Иван
    )




    preg_replace() - выполняет поиск и замену регулярного выражения.

    mixed preg_replace (mixed pattern, mixed replacement, mixed subject [, int limit])


    Ищет в subject совпадения с pattern и замещает их replacement. Если limit специфицирован, то замещаются только limit совпадений; если limit опущен или равен -1, замещаются все совпадения.

    Replacement может содержать ссылку в форме \\n или $n, где последняя форма предпочтительнее. Каждая такая ссылка замещается текстом, захваченным n'ным патэрном в скобках. n может быть от 0 до 99, а \\0 или $0 ссылаются на текст, совпавший со всем патэрном. Открывающие скобки подсчитываются слева направо (начиная с 1) для получения количества захватывающих субпатэрнов.

    Если совпадения найдены, возвращается новый subject, иначе subject возвращается без изменений.

    Каждый параметр preg_replace() может быть массивом.

    Если subject это массив, то поиск и замена выполняются в каждом вхождении subject, return-значение также будет массивом.

    Если pattern и replacement являются массивами, то preg_replace() принимает значение из каждого массива и использует их для выполнения поиска и замены в subject. Если replacement имеет меньше значений, чем pattern, то для оставшихся значений для замены используется пустая строка. Если pattern это массив, а replacement это строка, то эта замещающая строка используется для каждого значения pattern. Обратное не будет иметь смысла.

    Модификатор /e делает так, что preg_replace() рассматривает параметр replacement как PHP-код после выполнения соответствующей замены ссылок

    пример:

    <?php
    $text = "<b>Вася</b> любит <b>пиво</b> больше чем <b>Иван</b>";
    echo preg_replace("#<b>(.*)</b>#iU","[замена]", $text);
    ?>



    Этот пример даст:
    [замена] любит [замена] больше чем [замена]

    пример:

    <?php
    $text = "<b>Вася</b> любит <b>пиво</b> больше чем <b>Иван</b>";
    $search = array ("'Вася'i", "'пиво'i","'Иван'i");
    $replace = array ( "Катя","мороженное","Маша");
    echo preg_replace ($search, $replace, $text);
    ?>



    Этот пример даст:
    Катя любит мороженное больше чем Маша


    пример:

    <?php
    $text = "<b>Вася</b> любит <b>пиво</b> больше чем <b>Иван</b>";
    echo preg_replace ("#<b>(.*)</b>#iUe", "md5('\\1')",$text);
    ?>



    Этот пример даст:
    b212e4e8bc960592ff6571ffa6000a67 любит 07564df0646634634ddece185c65f5fc больше чем ff4650ffb21f59efd09de0193d8a928c
  • Patrick

    Сообщения: 506 Репутация: N Группа: Кто попало

    Spritz 20 июля 2007 г. 16:46, спустя 2 дня 7 часов 44 минуты

    http://devnotes.ru/regexp.png - Небольшая шпора!
  • md5

    Сообщения: 11949 Репутация: N Группа: в ухо

    Spritz 21 июля 2007 г. 10:07, спустя 17 часов 21 минуту 3 секунды

    хм, надо перевести эту шпору на русский для пиплов
    все умрут, а я изумруд
  • Patrick

    Сообщения: 506 Репутация: N Группа: Кто попало

    Spritz 21 июля 2007 г. 11:13, спустя 1 час 5 минут 26 секунд


    хм, надо перевести эту шпору на русский для пиплов
    да и на английском она читается вполне нормально…
  • welder

    Сообщения: 2945 Репутация: N Группа: в ухо

    Spritz 21 июля 2007 г. 11:57, спустя 44 минуты 37 секунд

    она и без коментов хорошо читаеться :)
  • adw0rd

    Сообщения: 22905 Репутация: N Группа: в ухо

    Spritz 18 августа 2007 г. 13:29, спустя 28 дней 1 час 32 минуты


    http://devnotes.ru/regexp.png - Небольшая шпора!


    Битая ссылко на шпору, 404 Not Found!

    Мож эта она, или не она… http://zeleboba.ru/file/regular_expressions_cheat_sheet.pdf
    adw/0
  • welder

    Сообщения: 2945 Репутация: N Группа: в ухо

    Spritz 20 августа 2007 г. 14:31, спустя 2 дня 1 час 1 минуту



    http://devnotes.ru/regexp.png - Небольшая шпора!


    Битая ссылко на шпору, 404 Not Found!

    Мож эта она, или не она… http://zeleboba.ru/file/regular_expressions_cheat_sheet.pdf



    http://www.ilovejackdaniels.com/cheat-sheets/regular-expressions-cheat-sheet/
  • aligator

    Сообщения: 52 Репутация: N Группа: Кто попало

    Spritz 20 августа 2007 г. 14:39, спустя 8 минут 4 секунды

    Спасибо тебя Welder.
  • gorgorgor

    Сообщения: 6 Репутация: N Группа: Кто попало

    Spritz 21 января 2008 г. 4:52, спустя 153 дня 15 часов 13 минут

    почему не работает модификатор "i" с русским шрифтом? подскажите как быть.
  • Timur

    Сообщения: 1068 Репутация: N Группа: Джедаи

    Spritz 21 января 2008 г. 11:08, спустя 6 часов 16 минут 2 секунды

    gorgorgor, покажи код, т.к. вообще-то должно работать
  • gorgorgor

    Сообщения: 6 Репутация: N Группа: Кто попало

    Spritz 21 января 2008 г. 21:43, спустя 10 часов 34 минуты 25 секунд

    if(preg_match("#код#i", $mes)) {…}

    находит только "код", но никак не "КОД"
  • gorgorgor

    Сообщения: 6 Репутация: N Группа: Кто попало

    Spritz 21 января 2008 г. 23:43, спустя 2 часа 12 секунд

    только что начитался про setlocale, ничего толком не понял. может кто-нибудь объяснить как нужно правильно сделать?
  • md5

    Сообщения: 11949 Репутация: N Группа: в ухо

    Spritz 22 января 2008 г. 4:41, спустя 4 часа 58 минут 21 секунду

    setlocale()
    все умрут, а я изумруд
  • disc

    Сообщения: 843 Репутация: N Группа: Джедаи

    Spritz 22 января 2008 г. 5:21, спустя 39 минут 43 секунды

    попробуй поставить флаг Юникода, может поможет помоему u
  • kendo

    Сообщения: 446 Репутация: N Группа: Адекваты

    Spritz 22 января 2008 г. 12:42, спустя 7 часов 21 минуту 31 секунду

    http://weitz.de/files/regex-coach.exe
    А вот в помощь программка для тестирования и наглядного представления регулярных выражений :) Правда, работает медленно (или это только на моей старой машине :))

Пожалуйста, авторизуйтесь, чтобы написать комментарий!