Статьи о регулярных выражениях (дубль два)

Yukko

Новичок
Статьи о регулярных выражениях (дубль два)

Стартанем в оффтопике... а там посмотрим, young непротив опубликовать статьи на detail при условии, что будет, что опубликовывать. Именно поэтому прошу обсудить все ляпы, ошибки, непонятки в тех текстах, которые я создал. Прошу читать всех, как начинающих, так и "зубров".
Первых попрошу написать, что описано непонятно, что следует объяснить лучше, вторых прошу описать ошибки и неточности и т.д.

Я абсолютно не претендую на оригинальность и не претендую на лавры Фридла, у кого есть возможность, прочтите лучше его книгу.

Поехали:
http://faq.webscript.ru/RegularExpressions/ForAbsoluteDoomies - статья написана для тех, кто вообще ничего не догоняет, так сказать, Регулярные выражения для чайников.

http://faq.webscript.ru/RegularExpressions - эту статью мы уже обсуждали, после обсуждения добавлены примеры с подробным описанием.

http://faq.webscript.ru/RegularExpressions2 - описаны наиболее часто встречающиеся спецсимволы, исползование альтернатив, приведены примеры.

http://faq.webscript.ru/RegularExpressions3 - использование ретроспективной и опережающей проверок тоже с примерами.

http://faq.webscript.ru/RegularExpressions/whyNotThisTime - когда и почему нельзя использовать регулярные выражения. Философские рассуждения по мотивам одного из топиков на этом форуме.
 

young

Новичок
Re: Статьи о регулярных выражениях (дубль два)

Мне понравилось.
Только я не люблю сериалы.

Ты мог бы оформить для деталей хотя бы в 2 статьи?

-~{}~ 29.02.04 10:07:

PS:
Правда, в будущем надо будет ожесточить требования к написанию статей по стилю написания.
 

si

Administrator
.webscript.ru/RegularExpressions3 - использование ретроспективной и опережающей проверок тоже с примерами.
имхо примеры не в тему, там не нужно ни опережающая не ретроспективная проверка. и смысл этих операций обсолютно не показан.
PHP:
$string = <<<EOD
<TD>20.02<BR>05:30
<TD class=l>Товар 1?<BR>Товар 2?
<TD><B>35</B>
<TD><A href="http://ссылка/" id=sfsd32dfs
onclick="return m(this)">26.92</A><BR><A href="http://ссылка/" 
id=r3_3143svsfd onclick="return m(this)">27.05</A>
<TD><B>270.5</B>
</TR>
EOD;

preg_match_all("/(?<=>)(\d*\.\d*)(?=<\/A>|<\/B>)/", $string, $matches); 
print_r($matches); 

preg_match_all("/>(\d*\.\d*)(?:<\/A>|<\/B>)/", $string, $matches); 
print_r($matches);
[output]
Array
(
[0] => Array
(
[0] => 26.92
[1] => 27.05
[2] => 270.5
)

[1] => Array
(
[0] => 26.92
[1] => 27.05
[2] => 270.5
)

)
Array
(
[0] => Array
(
[0] => >26.92</A>
[1] => >27.05</A>
[2] => >270.5</B>
)

[1] => Array
(
[0] => 26.92
[1] => 27.05
[2] => 270.5
)

)
[/output]

как видно результат можно получить и более простым и естественным способом.

а вот другой пример:
PHP:
$string = "abcd";

preg_match_all("/(?<=[ab])([bc])/", $string, $matches); 
print_r($matches); 

preg_match_all("/[ab]([bc])/", $string, $matches); 
print_r($matches);
[output]
Array
(
[0] => Array
(
[0] => b
[1] => c
)

[1] => Array
(
[0] => b
[1] => c
)

)
Array
(
[0] => Array
(
[0] => ab
)

[1] => Array
(
[0] => b
)

)
[/output]
тут как видим результат совсем другой
 

young

Новичок
все пять слить в две???
Я считаю что да. Но это мое личное мнение.
Публиковать ее в пяти сериях смысла нет (ИМХО).
Можно даже в одну слить.
Но лучше в две - для новичков и покрепче
 

Yukko

Новичок
si
Я все понимаю.
Я брал реальные примеры из жизни (с этого форума), описывал ход решения при помощи проверок. В любом случае это один из вариантов решения задачи, который, ИМХО, имеет право на жизнь.
Сразу же вопрос:
Есть ли примеры каких-нибудь наболевших задач (парсинг HTML, ini-подобных файлов, парсинг чего угодно, проверка валидности форм) где бы без использования проверок нельзя было бы обойтись? Не хотелось бы использовать надуманные примеры.
Сюда же:
Есть ли примеры, где необходимо использовать какой-то из негативных видов проверки?
Конечно можно поискать у Фридла, там это должно быть, но я дал себе зарок, что от начала создания до окончания к Фридлу не заглядывать :)

young
тогда
http://faq.webscript.ru/RegularExpressions/ForAbsoluteDoomies
http://faq.webscript.ru/RegularExpressions
http://faq.webscript.ru/RegularExpressions2
в одну статью, а
http://faq.webscript.ru/RegularExpressions3
http://faq.webscript.ru/RegularExpressions/whyNotThisTime
во вторую?
 

Макс

Старожил PHPClub
Yukko
по поводу позиционных проверок (ИМХО):
1. нужно указать что PCRE не позволяет делать проверки на совпадение текста произвольной длинны. То есть нельзя делать например такую проверку:
/(?<=\d+?)\w/
2. ИМХО ты начал со слишком уже сложного примера. Может сначало попроще. Например выбрать весь текст, который находится между тегами <b> .... </b> :
/(?<=<b>)[^<>]+?(<\/b>)/
3. Еще надо указать, что значения ретроспективных проверок не сохраняются (то есть в этом плане они сходны с (?:....))
 

Yukko

Новичок
Maxim Matyukhin:
весь текст, который находится между тегами <b> .... </b> :
а ты посмотри, как меня si привел к общему знаменателю со своим вариантом решения поставленной задачи :)

Что-то мне не нравится это РВ. Ты можешь объяснить каким образом вопросительный знак уймет жадность квантификатора '+' при использовании его в строке из цифр, в которой количество символов больше 1 (то, что ты его поставил в проверку просто опускаем, так как это невозможно)?

не позволяет делать проверки на совпадение текста произвольной длинны.
Укажу где-то...
Еще надо указать, что значения ретроспективных проверок не сохраняются
Согласен, добавлю.
 

si

Administrator
Maxim Matyukhin
смысл этих возможностей посмотреть назад или в перед, при этом они не меняют позицию поиска и не учитываются в совпадении, для всяких <b>.+?</b> они не нужны и могут быть вредны (не могу так сразу придумать пример нежелательного совпадения). посмотри внимательно на мой второй пример, там без ретроспективной проверки никак ты рег не напишешь как раз. так вот в статье вообще нераскрывается смыл этих конструкций. а я полез пока перечитаю кусок из книги по реги на счет этих проверок, сам не всегда до конца их понимаю :)
 

Yukko

Новичок
Кажется я придумал :) , если взять и изменить в том примере, который покритиковал si условие, что нужно найти все цены, которые не входят в теги <b>....</b> в приведенном примере это будет:
26.92
27.05
а цена
270.5 нам не нужна, тогда РВ поменяется на вот такое:
PHP:
preg_match_all("/(?<=>)(?<!<TD>)(\d*\.\d*)(?!<\/B> )(?=<)/", $string, $matches);
Замечания есть?

Что-то в таком духе... пойду покурю травы, проверю РВ.
(пробел перед скобкой вставляет)

внатуре вставляет :)
окончательный вариант уже имеет в себе отрицательную ретроспективную и опережающую проверки, так же следует написать, что различные идущие друг за другом проверки применяются независимо друг от друга в одной точке, не меняя ее... вот. Естественно, что совпадение будет найдено, если все проверки совпадут.
 

Макс

Старожил PHPClub
Yukko
Что-то мне не нравится это РВ.
я же написал что он нерабочий. И дело здесь не в жадности, а в том что нельзя в позиционных проверках использовать строки переменной длинны. Наверное такой пример будет более правильным (хотя в PCRE он все равно не будет работать):
/(?<=\w+\d) test/

А теперь по поводу первого рега, который si привел.
PHP:
preg_match_all("/(?<=>)(\d*\.\d*)(?=<\/A>|<\/B>)/", $string, $matches); 
print_r($matches);
дело в том, что здесь необязательно использовать сохраняющие скобки. Например если написать так:
PHP:
preg_match_all("/(?<=>)\d*\.\d*(?=<\/A>|<\/B>)/", $string, $matches); 
print_r($matches);
Вывод будет:
Код:
Array
(
    [0] => Array
        (
            [0] => 26.92
            [1] => 27.05
            [2] => 270.5
        )
)
что ИМХО более правильно чем было раньше. То есть за счет свойства несохранения результата происходит экономия памяти
 

si

Administrator
что ИМХО более правильно чем было раньше. То есть за счет свойства несохранения результата происходит экономия памяти
думаю сложность реализаяии заглядывания назад и вперед с лихвой компенсирует эту экономию :)

-~{}~ 29.02.04 19:04:

\d*\.\d* - вообще то неправильно, потому что совпадет с <b>.</b>
 

Yukko

Новичок
si насчет <b>.</b>:
от контекста все зависит... нет смысла усложнять, если нет смысла :) (Neo remake)

si насчет сложности реализации:
не думаю, что намного сложнее... в каждой точке без возвратов происходит локальный поиск совпадения позиционной проверки.

si и другие
есть замечания по поводу рега, который я привел в предыдущем посте? Он сложнее, чем первоначальный, но вроде удовлетворяет условию, что поиск нельзя провести без позиционных проверок, так же там есть еще негативные ретроспективная и опережающая проверки.

-~{}~ 04.03.04 00:53:

Переписал пример №1 в статье про позиционные проверки: http://faq.webscript.ru/RegularExpressions3
Дописал к нему три развернутых коментария, проверьте пожалуйста, правильно ли все?
 

Макс

Старожил PHPClub
а рег
\d*\.\d*
так и остался :(

-~{}~ 04.03.04 01:08:

вот у Фридла был пример, который мне очень помог в понимании. Суть рега была примерно в следующем:
/(?<=\d)(?=[a-z])/ (рег написан от балды - главное суть)
с чем совпадает этот рег ? С позицией между \d и [a-z], не со строкой, не с символом а именно с позицией.
Вот я почему-то только после такого примера стал нормально понимать эти позиционные проверки. Может стоит добавить

Подобная проверка иногда полезна когда нужно вставить что-то в существуюющую строку (не заменить подстроку на другую, а именно вставить). Например:
PHP:
$a = ' a5.555 b5555'; // нужно вставить пробелы между "соприкасающимися" цифрами и буквами
echo preg_replace("~(?<=[a-z])(?=\d)~", " ", $a);
 

Profic

just Profic (PHP5 BetaTeam)
Вот кое-какие ляпы заметил:
Вот и получается, что после пяти любых букв латинского алфавита идет 5 любых цифр. Поиск происходит точно также как я описывал выше, только символы в условии поиска задаются не явно, а при помощи символьных классов.
после пяти любых букв латинского алфавита = после четырёх любых букв латинского алфавита

Ясно, что применив условие поиска avcd{1,4}efg для строки abcefg, совпадение найдено не будет, так как квантификатор {1,4} подразумевает, что после abc перед efg идет миним одна, максимум четыре буквы d.
avcd{1,4}efg = abcd{1,4}efg
миним = минимум

preg_match("/$[a-z0-9]/", $string,$mathces);
"/$[a-z0-9]/" = "/^[a-z0-9]/"

\w - спецсимвол, который призван заменить целый символьный класс, в него входят все символы, которые могут входить в слово, обычно это [a-zA-Z_], хотя много может зависеть от установленной локали, поддержки юникода и т.д.
[a-zA-Z_] = [a-zA-Z0-9_] (A "word" character is any letter or digit or the underscore character) (c) Мануал :)
 
Сверху