Вернемся к квантификаторам (символам повтора)
"*" и
"+", по-умолчанию они являются жадными, т.е. они будут "съедать" текст максимально возможной длины, но такое поведение иногда может мешать.
Пример показывает извлечение текста, находящегося между тегами
и
Код
#include <Array.au3>
$sText = 'собака<td>слон</td><td>жираф</td><td>кот</td>рыба'
$sPattern = '<td>(.+)</td>'
$aResult = StringRegExp($sText, $sPattern, 3)
_ArrayDisplay($aResult)
В результате мы получили не совсем то, что хотели
Дело в том, что шаблон
"съел" весь текст между первым тегом
и последним
.
Для получения нужного результата нужно чтобы квантификатор
"+" стал ленивым, дописываем после него знак
"?" и тогда новый шаблон
будет "съедать" наименьший фрагмент текста:
Код
#include <Array.au3>
$sText = 'собака<td>слон</td><td>жираф</td><td>кот</td>рыба'
$sPattern = '<td>(.+?)</td>'
$aResult = StringRegExp($sText, $sPattern, 3)
_ArrayDisplay($aResult)
Можно сказать так: жадный квантификатор просматривает текст справа налево (с конца строки), а ленивый слева направо (с начала строки).
Кроме ленивого квантификаторы можно сделать ревнивыми (иногда такую квантификацию называют сверхжадностью или завистью). Такая квантификация не только захватывает текст максимальной длины, но и не отдает этот текст другим элементам шаблона.
Поясняющий пример:
Код
#include <Array.au3>
$sText = 'жираф!'
$sPattern = '(.+)!'
If StringRegExp($sText, $sPattern) Then
ConsoleWrite(StringRegExpReplace($sText, $sPattern, '$1') & @CRLF)
Else
ConsoleWrite('none' & @CRLF)
EndIf
Шаблон
"(.+)!" сработает примерно так: "(.+)" захватит весь текст, но поскольку после этого стоит "!", то он будет вынужден вернуть восклицательный знак, и на выходе мы будем иметь строку без ! в конце.
Пример с ревнивым квантификатором:
Код
#include <Array.au3>
$sText = 'жираф!'
$sPattern = '(.++)!'
If StringRegExp($sText, $sPattern) Then
ConsoleWrite(StringRegExpReplace($sText, $sPattern, '$1') & @CRLF)
Else
ConsoleWrite('none' & @CRLF)
EndIf
"(.++)" "съест" весь текст и не отдаст последний символ для "!", поэтому выражение не даст совпадений шаблону.
Для чего же нужен такой "бестолковый" квантификатор? В первую очередь для ускорения работы регулярных выражений, ведь при проверке шаблонов много времени тратится именно на возвраты, непосредственно в алгоритмах поиска текста ревнивые квантификаторы используются крайне редко.
Прирост скорости при использовании ревнивых квантификаторов мизерный, так что использовать их или нет решайте сами
, но медленнее ваши выражения не станут точно. Использовать их надо так, чтобы они захватывали только нужный текст.
Пример:
Код
$sText = 'abc123abc123'
$sPattern = '(\d+)'
$hTimer = TimerInit()
For $i = 1 To 100000
$aResult = StringRegExp($sText, $sPattern, 3)
Next
ConsoleWrite(TimerDiff($hTimer) & @CRLF)
$sPattern = '(\d++)'
$hTimer = TimerInit()
For $i = 1 To 100000
$aResult = StringRegExp($sText, $sPattern, 3)
Next
ConsoleWrite(TimerDiff($hTimer) & @CRLF)
В примере шаблон
"(\d++)", не может захватить "лишний" текст, поэтому работает верно.
И несколько ссылок на темы, где в решениях применялись ревнивые квантификаторы:
http://autoit-script.ru/index.php?topic=1567.0
http://autoit-script.ru/index.php?topic=1483.0
http://autoit-script.ru/index.php?topic=741.0