Урок 2. Шаблоны
Урок 3. Специальные приемы
Урок 4. Практика
Урок 5. Другие RegExp в AutoIt
Замечания, дополнения и исправления приветствуются (здесь)!
Урок 4. Практика
Выбор инструмента
Для решения любой задачи с использованием RegExp необходимо определить что нужно получить в итоге, и выбрать инструмент.
Задачи, которые решаются с помощью RegExp (из первого урока):
Это случай, когда нужно проверить текст на соответствие его какой-то структуре/правилу/порядку размещения символов в строке/и т.п.
Для этого подойдет
данная функция выдаст 0 или 1, в зависимости от совпадения шаблона с текстом.
Это случай, когда необходимо заменить в тексте какие-либо символы/слова/сочетания слов на что-то другое или поменять их порядок.
Для простых замен в тексте (например: "Петя" на "Вася" или буквы "ё" на "е") лучше использовать функцию StringReplace - она быстрее и проще.
В более сложных случаях используйте StringRegExpReplace
Это случай, когда на выходе нам нужно получить какой-то элемент текста - слово/значение параметра/массив элементов текста/и т.п.
Для извлечения одного определенного элемента, как правило уникального, (например, название трека из ID3-Tag для mp3-файла, или все теги из файла, но одной строкой) из всего текста используется StringRegExpReplace с использованием обратных ссылок, при этом можно проделать некоторые перестановки внутри результирующей строки. Также используется StringgRegExp с флагами 1 или 3, где на выходе получится удобный массив с одним или несколькими значениями.
Для извлечения множества подобных элементов (например, всех ссылок из html-документа) из текста в массив используется StringRegExp с флагом 3.
- Проверка соответствия текста заданному шаблону
Это случай, когда нужно проверить текст на соответствие его какой-то структуре/правилу/порядку размещения символов в строке/и т.п.
Для этого подойдет
Код
StringRegExp($sText, $sPattern, 0)
; или короче:
StringRegExp($sText, $sPattern)
; т.к. 0 - это флаг по-умолчанию
; или короче:
StringRegExp($sText, $sPattern)
; т.к. 0 - это флаг по-умолчанию
данная функция выдаст 0 или 1, в зависимости от совпадения шаблона с текстом.
- Изменение информации в тексте
Это случай, когда необходимо заменить в тексте какие-либо символы/слова/сочетания слов на что-то другое или поменять их порядок.
Для простых замен в тексте (например: "Петя" на "Вася" или буквы "ё" на "е") лучше использовать функцию StringReplace - она быстрее и проще.
В более сложных случаях используйте StringRegExpReplace
- Извлечение информации из текста
Это случай, когда на выходе нам нужно получить какой-то элемент текста - слово/значение параметра/массив элементов текста/и т.п.
Для извлечения одного определенного элемента, как правило уникального, (например, название трека из ID3-Tag для mp3-файла, или все теги из файла, но одной строкой) из всего текста используется StringRegExpReplace с использованием обратных ссылок, при этом можно проделать некоторые перестановки внутри результирующей строки. Также используется StringgRegExp с флагами 1 или 3, где на выходе получится удобный массив с одним или несколькими значениями.
Для извлечения множества подобных элементов (например, всех ссылок из html-документа) из текста в массив используется StringRegExp с флагом 3.
Практические примеры
Не буду приводить примеров для проверки соответствия текста шаблону, т.к. такие RegExp ничем не отличаются от других, кроме информативности - она крайне скудна.
Извлечение информации
Задача:
С сайта гисметео получить текущую температуру за окном для города Ялта.
Решение:
Заходим на этот сайт любым браузером, ищем ссылку для города Ялта и переходим по ней
Далее можно найти решение через библиотеку _IE с использованием коллекций и прочих финтифлюшек. Но мы будем решать с использованием сурового RegExp!
Для этого нам необходимо получить каркас этой html-страницы в скрипт:
Способ 1:
Код
#include <IE.au3>
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oIE = _IECreate($sUrl)
$sHTML = _IEBodyReadHTML($oIE)
ConsoleWrite($sHTML & @CRLF)
Способ 2:
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
ConsoleWrite($sHTML & @CRLF)
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
ConsoleWrite($sHTML & @CRLF)
Способ 3:
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$sHTML = BinaryToString(InetRead($sUrl), 4)
ConsoleWrite($sHTML & @CRLF)
$sHTML = BinaryToString(InetRead($sUrl), 4)
ConsoleWrite($sHTML & @CRLF)
Все способы имеют право жить и вполне рабочие, критических различий между результатами нет, кроме знака "градус" - первый способ выводит его одним символом, а второй и третий в виде "°",
Теперь нам нужно проанализировать полученный текст. Копируем полученный текст из консоли в любой редактор (желательно с подсветкой html-тегов для удобства) можно даже в сам SciTE, и ищем искомую температуру "+27". Итог поисков приводит нас к фрагменту:
Код
<div class="rframe" id="weather"><div class="fcontent">
<h2>Погода за окном</h2>
<div class="section">
<h3 class="typeM">Ялта</h3>
<div class="scity"><a href="/catalog/ukraine/316/">Крым АР</a> / <a href="/catalog/ukraine/">Украина</a></div>
<dl class="cloudness">
<dt class="png" style="background-image: url(http://i.gismeteo.com/static/images/icons/new/d.sun.png)"><br></dt>
<dd>Ясно</dd>
</dl>
<div class="temp">+27°C</div>
<div class="wicon barp">754<span class="unit">мм рт.ст.</span></div>
<div class="wicon wind"><dl title="Южный" class="wicon wind5"><dt>Ю</dt><dd>2<span class="unit">м/с</span></dd></dl></div>
<div class="wicon hum">21<span class="unit">%</span></div>
<div class="wrap f_link">
<span class="icon date">04.06.2011 9:00:00</span>
<a class="icon fcast" href="/city/daily/5002/">Прогноз</a>
</div>
</div><!--block expire GMT+0: 2011-06-04 8:43:10--> </div></div>
<h2>Погода за окном</h2>
<div class="section">
<h3 class="typeM">Ялта</h3>
<div class="scity"><a href="/catalog/ukraine/316/">Крым АР</a> / <a href="/catalog/ukraine/">Украина</a></div>
<dl class="cloudness">
<dt class="png" style="background-image: url(http://i.gismeteo.com/static/images/icons/new/d.sun.png)"><br></dt>
<dd>Ясно</dd>
</dl>
<div class="temp">+27°C</div>
<div class="wicon barp">754<span class="unit">мм рт.ст.</span></div>
<div class="wicon wind"><dl title="Южный" class="wicon wind5"><dt>Ю</dt><dd>2<span class="unit">м/с</span></dd></dl></div>
<div class="wicon hum">21<span class="unit">%</span></div>
<div class="wrap f_link">
<span class="icon date">04.06.2011 9:00:00</span>
<a class="icon fcast" href="/city/daily/5002/">Прогноз</a>
</div>
</div><!--block expire GMT+0: 2011-06-04 8:43:10--> </div></div>
В этом фрагменте нас интересует только
Код
<div class="temp">+27°C</div>
По идее все - можно вставлять обрамляющие теги в RegExp и мы получим то, что хотим. Но если внимательно просмотреть весь текст, то можно найти несколько таких тегов
Код
<div class="temp">
Код
<div class="wtabs wrap">
<span class="prev"></span>
<a href="/city/daily/5002/2/" class="next"></a>
<div class="wtab swtab" id="tab_wdaily1">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap weekend"><dt>СБ</dt><dd>04.06</dd></dl>
<div class="temp">+20°..<em>+27</em>°</div>
</div>
<div class="wtab" id="tab_wdaily2">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap weekend"><dt>ВС</dt><dd>05.06</dd></dl>
<div class="temp">+21°..<em>+25</em>°</div>
</div>
<div class="wtab" id="tab_wdaily3">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap"><dt>ПН</dt><dd>06.06</dd></dl>
<div class="temp">+20°..<em>+25</em>°</div>
</div>
</div>
<span class="prev"></span>
<a href="/city/daily/5002/2/" class="next"></a>
<div class="wtab swtab" id="tab_wdaily1">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap weekend"><dt>СБ</dt><dd>04.06</dd></dl>
<div class="temp">+20°..<em>+27</em>°</div>
</div>
<div class="wtab" id="tab_wdaily2">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap weekend"><dt>ВС</dt><dd>05.06</dd></dl>
<div class="temp">+21°..<em>+25</em>°</div>
</div>
<div class="wtab" id="tab_wdaily3">
<img class="cloudness png" src="http://i.gismeteo.com/static/images/icons/new/d.sun.c2.r1.png" alt="">
<dl class="date wrap"><dt>ПН</dt><dd>06.06</dd></dl>
<div class="temp">+20°..<em>+25</em>°</div>
</div>
</div>
Чем же отличаются эти два фрагмента?
Код
Во-первых, у них разные "родительские" контейнеры (<div class="rframe" id="weather"> и <div class="wtabs wrap">), которые больше нигде не повторяются, а это именно то к чему необходимо "привязываться" при составлении RegExp.
Во-вторых, второй фрагмент внутри <div class="temp"></div> содержит теги "em".
В-третьих, можно заметить, что искомый нам тег идет первым среди <div class="temp"> во всем тексте - это тоже можно использовать.
В-четвертых, формат искомых данных выглядит так - "знак, цифры и "°C", и он не похож на другие контейнера <div class="temp"></div> (ни один из них не заканчивается знаком "C").
Преобразования из "°C" в "°C" будем проделывать через StringReplace, преобразование с помощью самого выражения используем только в четвертом способе, т.к. при такой замене первые три способа сведутся к четвертому

Вы сами при желании можете найти еще множество зацепок, к которым можно "привязаться".
Мы решим эту задачу четырьмя способами!
Способ 1. С учетом родительского контейнера
Составляем шаблон:
1. Следует учесть флаги. Т.к. html-документ может содержать теги вида
Код
<div>/<DIV>/<Div>
2. Нам нужно учесть родительский контейнер
Код
"<div class="rframe" id="weather">"
Код
(?si)<div class="rframe" id="weather">
3. Учтем все, что идет до тега "
"
4. Впишем сам тег "
Код
(?si)<div class="rframe" id="weather">.*?
4. Впишем сам тег "
":
5. Добавим группу с захватом:
6. Впишем символ нового тега "<", для ограничения группы с захватом:
Собственно, шаблон готов, его можно уже использовать, но давайте его еще подсократим -
поскольку слово ["weather"] встречается единожды во всем тексте - смело удаляем всё, что идет в этом теге кроме него, а так же заменим пробелы на "\s" в результате получаем:
Важно! Этот шаблон можно использовать в StringRegExp, а вот для того, чтобы использовать этот шаблон в StringRegExpReplace к нему нужно добавить ".*?" ("?" не даст "съесть" слишком много текста, до того как он встретит сочетание, описанное в шаблоне далее) в начале и ".*" в конце шаблона, т.к. при выдаче результата с использованием обратных ссылок, шаблон должен включать в себя весь текст, а не только его ключевой кусок.
Такой шаблон найдет в тексте слово "weather", затем первый идущий за ним контейнер класса "temp" и выдаст его содержимое.
Способ 2. С учетом отсутствия дочерних "em" и "/em" тегов
1. Берем флаги из способа №1
2. Дописываем искомый контейнер класса "temp", группу с захватом за ним и знак закрывающегося тега "":
3. Исключаем попадание в группу с захватом любых тегов (в том числе и "em" с "/em"), простой заменой "." на набор типа "ни один символ из набора", куда включим знак открывающегося тега "<":
Шаблон готов!
Этот шаблон найдет в тексте контейнер класса "temp", после чего начнет "есть" всё кроме знака "<", после группы он должен встретить "" и такое возможно только в контейнере без вложенных тегов.
Способ 3. С использованием расположения в тексте - первый тег среди всех и есть искомый
1. Берем стандартные флаги.
2. Дописываем искомый контейнер класса "temp", группу с захватом за ним и знак "<":
Шаблон готов!
Данный шаблон найдет в тексте контейнер класса "temp" и "съест" все до от ">" до следующего "<".
Способ 4. С описанием формата искомой строки
1. Берем стандартные флаги.
2. Дописываем искомый контейнер класса "temp".
3. Дописываем группу с захватом:
Расшифровка:
"(\+|-)?" - знак плюс или минус, который может быть или нет (при температуре 0 град.)
"\d+" - любой количество цифровых символов, но минимум один
4. Дописываем, то что должно идти после цифр до закрытия контейнера:
Шаблон готов!
Такой шаблон найдет контейнер класса "temp", затем знак плюс или минус, которого может и не быть, после которого идут цифры и строка "°C".
Обратите внимание на "$1°C" в конце выражения - это выдаст соответствие первой обратной ссылке "знак и число" и допишет после них знак градуса и букву "C".
Итог: все способы выдадут одинаковый результат. Способ №4 наиболее рациональный, также отмечу способ №2 - он независит от расположения других тегов и от расположения контейнера в тексте.
Код
(?si)<div class="rframe" id="weather">.*?<div class="temp">
5. Добавим группу с захватом:
Код
(?si)<div class="rframe" id="weather">.*?<div class="temp">(.*?)
6. Впишем символ нового тега "<", для ограничения группы с захватом:
Код
(?si)<div class="rframe" id="weather">.*?<div class="temp">(.*?)<
Собственно, шаблон готов, его можно уже использовать, но давайте его еще подсократим -
поскольку слово ["weather"] встречается единожды во всем тексте - смело удаляем всё, что идет в этом теге кроме него, а так же заменим пробелы на "\s" в результате получаем:
Код
"(?si)"weather".*?<div\sclass="temp">(.*?)<"
Важно! Этот шаблон можно использовать в StringRegExp, а вот для того, чтобы использовать этот шаблон в StringRegExpReplace к нему нужно добавить ".*?" ("?" не даст "съесть" слишком много текста, до того как он встретит сочетание, описанное в шаблоне далее) в начале и ".*" в конце шаблона, т.к. при выдаче результата с использованием обратных ссылок, шаблон должен включать в себя весь текст, а не только его ключевой кусок.
Такой шаблон найдет в тексте слово "weather", затем первый идущий за ним контейнер класса "temp" и выдаст его содержимое.
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?"weather".*?<div\sclass="temp">(.*?)<.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?"weather".*?<div\sclass="temp">(.*?)<.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
Способ 2. С учетом отсутствия дочерних "em" и "/em" тегов
1. Берем флаги из способа №1
2. Дописываем искомый контейнер класса "temp", группу с захватом за ним и знак закрывающегося тега "":
Код
"(?si)<div\sclass="temp">(.*?)</"
3. Исключаем попадание в группу с захватом любых тегов (в том числе и "em" с "/em"), простой заменой "." на набор типа "ни один символ из набора", куда включим знак открывающегося тега "<":
Код
"(?si)<div\sclass="temp">([^<]*?)</"
Шаблон готов!
Этот шаблон найдет в тексте контейнер класса "temp", после чего начнет "есть" всё кроме знака "<", после группы он должен встретить "" и такое возможно только в контейнере без вложенных тегов.
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?<div\sclass="temp">([^<]*?)</.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?<div\sclass="temp">([^<]*?)</.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
Способ 3. С использованием расположения в тексте - первый тег среди всех
Код
<div class="temp">
1. Берем стандартные флаги.
2. Дописываем искомый контейнер класса "temp", группу с захватом за ним и знак "<":
Код
"(?si)<div\sclass="temp">(.*?)<"
Шаблон готов!
Данный шаблон найдет в тексте контейнер класса "temp" и "съест" все до от ">" до следующего "<".
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?<div\sclass="temp">(.*?)<.*', '$1')
;такой шаблон найдет последний контейнер класса "temp":
;$sResult = StringRegExpReplace($sHTML, '(?si).*<div\sclass="temp">(.*?)<.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si).*?<div\sclass="temp">(.*?)<.*', '$1')
;такой шаблон найдет последний контейнер класса "temp":
;$sResult = StringRegExpReplace($sHTML, '(?si).*<div\sclass="temp">(.*?)<.*', '$1')
$sResult = StringReplace($sResult, '°', '°')
ConsoleWrite($sResult & @CRLF)
Способ 4. С описанием формата искомой строки
1. Берем стандартные флаги.
2. Дописываем искомый контейнер класса "temp".
Код
"(?si)<div\sclass="temp">"
3. Дописываем группу с захватом:
Код
"(?si)<div\sclass="temp">((\+|-)?\d+)"
Расшифровка:
"(\+|-)?" - знак плюс или минус, который может быть или нет (при температуре 0 град.)
"\d+" - любой количество цифровых символов, но минимум один
4. Дописываем, то что должно идти после цифр до закрытия контейнера:
Код
"(?si)<div\sclass="temp">((\+|-)?\d+)°C"
Шаблон готов!
Такой шаблон найдет контейнер класса "temp", затем знак плюс или минус, которого может и не быть, после которого идут цифры и строка "°C".
Код
$sUrl = 'http://www.gismeteo.ru/city/daily/5002/'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si)<div\sclass="temp">[/b]((\+|-)?\d+)°C', '$1°C')
ConsoleWrite($sResult & @CRLF)
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$sResult = StringRegExpReplace($sHTML, '(?si)<div\sclass="temp">[/b]((\+|-)?\d+)°C', '$1°C')
ConsoleWrite($sResult & @CRLF)
Обратите внимание на "$1°C" в конце выражения - это выдаст соответствие первой обратной ссылке "знак и число" и допишет после них знак градуса и букву "C".
Итог: все способы выдадут одинаковый результат. Способ №4 наиболее рациональный, также отмечу способ №2 - он независит от расположения других тегов и от расположения контейнера
Код
"<div class="temp">"
Задача:
С сайта сбербанка получить значение курса основных валют и драгоценных металлов.
Решение:
Как и в примере №1 находим кусок кода, на котором находятся интересующие нас значения:
Код
...
<td class="img"><img src="/common/img/eggs/strelka_grin2.gif" width="5" height="3" alt="повышение" title="повышение: 0,05"></td>
<td style="font-weight:bold;font-size:14px;color:#339900">
27,5 </td>
<td class="img"><img src="/common/img/eggs/strelka_grin2.gif" width="5" height="3" alt="повышение" title="повышение: 0,05"></td>
<td style="font-weight:bold;font-size:14px;color:#339900">
28,2 </td>
...
<td style="font-weight:bold;font-size:14px">
40,3 </td>
<td class="img"><img src="/common/img/0.gif" width="5" height="3" alt=""></td>
<td style="font-weight:bold;font-size:14px">
41,05 </td>
...
<td style="font-weight:bold;font-size:14px">1357</td>
<td class="img"><img src="/common/img/0.gif" width="5" height="3" alt=""></td>
<td style="font-weight:bold;font-size:14px">
1405 </td>
</tr>
<tr style="height: 21px;">
<td style="text-align:center; width:30px;">
<a href="/moscow/ru/quotes/metals/timeline/index.php?qid190=6">
...
<td style="font-weight:bold;font-size:14px;color:#cc0000">31,84</td>
<td class="img"><img src="/common/img/eggs/strelka_red2.gif" width="5" height="3" alt="падение" title="падение: -0,12"></td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">
33,76 </td>
<td class="img"><img src="/common/img/eggs/strelka_grin2.gif" width="5" height="3" alt="повышение" title="повышение: 0,05"></td>
<td style="font-weight:bold;font-size:14px;color:#339900">
27,5 </td>
<td class="img"><img src="/common/img/eggs/strelka_grin2.gif" width="5" height="3" alt="повышение" title="повышение: 0,05"></td>
<td style="font-weight:bold;font-size:14px;color:#339900">
28,2 </td>
...
<td style="font-weight:bold;font-size:14px">
40,3 </td>
<td class="img"><img src="/common/img/0.gif" width="5" height="3" alt=""></td>
<td style="font-weight:bold;font-size:14px">
41,05 </td>
...
<td style="font-weight:bold;font-size:14px">1357</td>
<td class="img"><img src="/common/img/0.gif" width="5" height="3" alt=""></td>
<td style="font-weight:bold;font-size:14px">
1405 </td>
</tr>
<tr style="height: 21px;">
<td style="text-align:center; width:30px;">
<a href="/moscow/ru/quotes/metals/timeline/index.php?qid190=6">
...
<td style="font-weight:bold;font-size:14px;color:#cc0000">31,84</td>
<td class="img"><img src="/common/img/eggs/strelka_red2.gif" width="5" height="3" alt="падение" title="падение: -0,12"></td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">
33,76 </td>
Конкретно нам нужны значения из этих ячеек:
Код
<td style="font-weight:bold;font-size:14px;color:#339900">
27,5 </td>
<td style="font-weight:bold;font-size:14px;color:#339900">
28,2 </td>
<td style="font-weight:bold;font-size:14px">
40,3 </td>
<td style="font-weight:bold;font-size:14px">
41,05 </td>
<td style="font-weight:bold;font-size:14px">1357</td>
<td style="font-weight:bold;font-size:14px">
1405 </td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">31,84</td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">
33,76 </td>
27,5 </td>
<td style="font-weight:bold;font-size:14px;color:#339900">
28,2 </td>
<td style="font-weight:bold;font-size:14px">
40,3 </td>
<td style="font-weight:bold;font-size:14px">
41,05 </td>
<td style="font-weight:bold;font-size:14px">1357</td>
<td style="font-weight:bold;font-size:14px">
1405 </td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">31,84</td>
<td style="font-weight:bold;font-size:14px;color:#cc0000">
33,76 </td>
Нужные нам значения находятся в ячейках таблицы, стиль которых различается только цветом текста (красный, зеленый или черный), текст внутри ячеек состоит из пробелов, цифр и знака ",", других ячеек с такими параметрами на странице нет.
Составляем шаблон:
1. Используем стандартные флаги.
2. Дописываем строку с ячейкой и частью ее стиля, в качестве цвета или его отсутствия используем конструкцию ".*?>":
Код
(?si)<td style="font-weight:bold;font-size:14px.*?>
3. Добавляем группу с захватом в которую попадут только цифровые символы и запятая, перед группой добавим возможные пробелы:
Код
(?si)<td style="font-weight:bold;font-size:14px.*?>\s*([\d,]+)
Шаблон готов!
Код
#include <Array.au3>
$sUrl = 'http://sbrf.ru'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$aResult = StringRegExp($sHTML, '(?si)<td style="font-weight:bold;font-size:14px.*?>\s*([\d,]+)', 3)
_ArrayDisplay($aResult)
$sUrl = 'http://sbrf.ru'
$oHTTP = ObjCreate('WinHttp.WinHttpRequest.5.1')
$oHTTP.Open('GET', $sUrl, False)
$oHTTP.Send('')
$oHTTP.WaitForResponse
$sHTML = $oHTTP.ResponseText
$aResult = StringRegExp($sHTML, '(?si)<td style="font-weight:bold;font-size:14px.*?>\s*([\d,]+)', 3)
_ArrayDisplay($aResult)
Пример выдаст массив со всеми значениями курсов валют и металлов, дальше можно делать с ними что угодно.
Дано:
Строка с параметрами и их значениями, параметры могут иметь разные значения или не иметь их, в названии параметров не может быть пробелов, между собой параметры разделены одиночной табуляцией:
Код
id=10 money=0 age= name=John Doe status= City=none nationality=
Задача:
Получить массив параметров и их значений.
Решение:
1. Обойдемся без флагов.
2. Пишем шаблон для параметров - любые символы кроме пробелов, минимум 1 символ:
([^\s]+)
3. Дописываем разделитель "="
([^\s]+)=
4. Дописываем вторую часть для значений параметров - любые символы кроме табуляции (в том числе и 0 символов для случая, когда значение параметра не указано):
([^\s]+)=([^\t]*)
Шаблон готов!
Код
#include <Array.au3>
$sStr = 'id=10'&@TAB&'money=0'&@TAB&'age='&@TAB&'name=John Doe'&@TAB&'status='&@TAB&'City=none'&@TAB&'nationality='
$aResult = StringRegExp($sStr, '([^\s]+)=([^\t]*)', 3)
_ArrayDisplay($aResult)
$sStr = 'id=10'&@TAB&'money=0'&@TAB&'age='&@TAB&'name=John Doe'&@TAB&'status='&@TAB&'City=none'&@TAB&'nationality='
$aResult = StringRegExp($sStr, '([^\s]+)=([^\t]*)', 3)
_ArrayDisplay($aResult)
Примечание: при копировании с форума отступы табуляции теряются или преобразовываются, поэтому в примере табуляция выставлена принудительно, но вы можете расставить табуляцию самостоятельно и проверить работу скрипта при этом.
Усложним задачу - пусть параметры между собой разделяются простыми пробелами:
Код
id=10 money=0 age= name=John Doe status= City=none nationality=
Решение:
1. Первую часть оставим без изменений:
([^\s]+)=
2. Часть со значениями параметров должна включать в себя все что идет перед следующим параметром, т.е. перед словом, за которым стоит знак "=" или, в случае когда это последний параметр в строке - всё до конца строки.
Здесь мы воспользуемся позитивным просмотром вперед.
Дополним шаблон группой с захватом, после которой идет или отсутствует (для последнего параметра в строке)пробел, затем записано условие просмотра вперед, да не простое, а с выбором из двух значений:
([^\s]+)=(.*?)\s?(?=[^\s]+=|$)
Расшифровка условия просмотра:
"?=" - позиция перед...
"[^\s]+=" - ... любым количеством символов, за исключением пробелов, за которым идет знак "="
"|$" - ...или концом строки
Т.е. выражение после того как найдет знак "=" будет искать пробел (который может и отсутствовать), чтобы пробелы не попали в итоговый массив, а затем оно будет искать такую позицию курсора, при которой за ним идет следующий параметр со знаком "=" или конец строки.
Код
#include <Array.au3>
$sStr = 'id=10 money=0 age= name=John Doe status= City=none nationality='
$aResult = StringRegExp($sStr, '([^\s]+)=(.*?)\s?(?=[^\s]+=|$)', 3)
_ArrayDisplay($aResult)
$sStr = 'id=10 money=0 age= name=John Doe status= City=none nationality='
$aResult = StringRegExp($sStr, '([^\s]+)=(.*?)\s?(?=[^\s]+=|$)', 3)
_ArrayDisplay($aResult)
Изменение информации (замена)
Дано:
css-код:
Код
body{
margin: 0;
padding: 0;
background-color: #СССССС;
font-family: Tahoma, Verdana;
font-size: 10pt;
font-weight: bold;
white-space: nowrap;
}
.cont{
border: 10px solid #000000;
background-color: #DDDDDD;
clear: both;
height: 150px;
padding: 10px;
margin: 4px;
}
margin: 0;
padding: 0;
background-color: #СССССС;
font-family: Tahoma, Verdana;
font-size: 10pt;
font-weight: bold;
white-space: nowrap;
}
.cont{
border: 10px solid #000000;
background-color: #DDDDDD;
clear: both;
height: 150px;
padding: 10px;
margin: 4px;
}
Задача:
Изменить значение background-color для блока ".cont"
Решение:
Поскольку background-color встречается несколько раз, то придется "цепляться" за сам блок ".cont".
Составляем шаблон:
1. Т.к. текст многострочный, то используем флаг "(?s)"
2. Допишем строку для имени блока:
(?s)\.cont{
3. Добавим строки до background-color заменив на стандартное ".*?" и допишем саму строку без параметра:
(?s)\.cont{.*?background-color:\s#
4. Добавляем группу с захватом, для значения параметра до ";":
(?s)\.cont{.*?background-color:\s#([^;]*)
5. Поскольку StringRegExpReplace при заменах использует весь описанный текст шаблона, то нужно весь текст слева от группы с захватом также добавить в такую группу для дальнейшей выдачи через обратную ссылку:
(?s)(\.cont{.*?background-color:\s#)([^;]*)
Шаблон готов!
Код
$sCSS = 'body{' & @CRLF
$sCSS &= ' margin: 0;' & @CRLF
$sCSS &= ' padding: 0;' & @CRLF
$sCSS &= ' background-color: #СССССС;' & @CRLF
$sCSS &= ' font-family: Tahoma, Verdana;' & @CRLF
$sCSS &= ' font-size: 10pt;' & @CRLF
$sCSS &= ' font-weight: bold;' & @CRLF
$sCSS &= ' white-space: nowrap;' & @CRLF
$sCSS &= '}' & @CRLF
$sCSS &= '' & @CRLF
$sCSS &= '.cont{' & @CRLF
$sCSS &= ' border: 10px solid #000000;' & @CRLF
$sCSS &= ' background-color: #DDDDDD;' & @CRLF
$sCSS &= ' clear: both;' & @CRLF
$sCSS &= ' height: 150px;' & @CRLF
$sCSS &= ' padding: 10px;' & @CRLF
$sCSS &= ' margin: 4px;' & @CRLF
$sCSS &= '}' & @CRLF
$sColor = 'FFFFFF'
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sCSS & @CRLF)
$sResult = StringRegExpReplace($sCSS, '(?s)(\.cont{.*?background-color:\s#)([^;]*)', '${1}' & $sColor)
ConsoleWrite('After --------------' & @CRLF)
ConsoleWrite($sResult & @CRLF)
$sCSS &= ' margin: 0;' & @CRLF
$sCSS &= ' padding: 0;' & @CRLF
$sCSS &= ' background-color: #СССССС;' & @CRLF
$sCSS &= ' font-family: Tahoma, Verdana;' & @CRLF
$sCSS &= ' font-size: 10pt;' & @CRLF
$sCSS &= ' font-weight: bold;' & @CRLF
$sCSS &= ' white-space: nowrap;' & @CRLF
$sCSS &= '}' & @CRLF
$sCSS &= '' & @CRLF
$sCSS &= '.cont{' & @CRLF
$sCSS &= ' border: 10px solid #000000;' & @CRLF
$sCSS &= ' background-color: #DDDDDD;' & @CRLF
$sCSS &= ' clear: both;' & @CRLF
$sCSS &= ' height: 150px;' & @CRLF
$sCSS &= ' padding: 10px;' & @CRLF
$sCSS &= ' margin: 4px;' & @CRLF
$sCSS &= '}' & @CRLF
$sColor = 'FFFFFF'
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sCSS & @CRLF)
$sResult = StringRegExpReplace($sCSS, '(?s)(\.cont{.*?background-color:\s#)([^;]*)', '${1}' & $sColor)
ConsoleWrite('After --------------' & @CRLF)
ConsoleWrite($sResult & @CRLF)
Шаблон найдет нужную конструкцию из первой группы с захватом и запишет ее как "$1", а затем найдет соответствие второй группе и заменит ее на новый цвет из переменной "$sColor".
Задача:
Произвести форматирование многострочного текста так, чтобы все знаки запятых между словами стояли сразу за первым словом, но через один пробел от следующего слова ("слово1, слово2"). При этом учесть возможность "висячих" запятых в начале строки и перенести в конец предыдущей.
Код
string,string, string ,string , string string , string,
string string
string ,string
string , string
string,string
,string ,string
, string , string
,string,string
, string ,string
string string
string ,string
string , string
string,string
,string ,string
, string , string
,string,string
, string ,string
Решение:
В задаче есть два вида запятых - внутри текста и в начале строки. В первом случае нужно заменить запятую со всеми окружающими ее пробелами на "{,}{пробел}", а во втором начало новой строки с запятой и всеми пробелами до и после них на "{,}{пробел}{перенос строки}". Значит, и выражений потребуется два - по одному для каждого случая.
1. Составим шаблон для запятой внутри строки.
В нем ничего сложного - нам нужно учесть пробелы до запятой и после нее (не важно сколько их и есть ли они вообще):
(\h*,\h*)
т.е. любое количество горизонтальных пробельных символов (0 или более штук) одна запятая и снова любое количество горизонтальных пробелов
2. Составим шаблон для запятой в начале новой строки:
Просто допишем к предыдущему шаблону конструкцию:
\h*\v+
т.е. любое количество горизонтальных пробельных символов и один или более "вертикальных пробелов", ими могут быть символы новой строки или возврата каретки (подробнее здесь).
Итоговый шаблон:
(\h*\v+\h*,\h*)
Сами замены смотрите в примере:
Код
$sText = 'string,string, string ,string , string string , string,' & @CRLF
$sText &= 'string string' & @CRLF
$sText &= 'string ,string' & @CRLF
$sText &= 'string , string' & @CRLF
$sText &= 'string,string' & @CRLF
$sText &= ',string ,string' & @LF
$sText &= ' , string , string' & @LF
$sText &= ' ,string,string' & @LF
$sText &= ', string ,string' & @CRLF
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '(\h*,\h*)', ', ')
ConsoleWrite('After1 -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '(\h*\v+\h*,\h*)', ', ' & @CRLF)
ConsoleWrite('After2 -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText &= 'string string' & @CRLF
$sText &= 'string ,string' & @CRLF
$sText &= 'string , string' & @CRLF
$sText &= 'string,string' & @CRLF
$sText &= ',string ,string' & @LF
$sText &= ' , string , string' & @LF
$sText &= ' ,string,string' & @LF
$sText &= ', string ,string' & @CRLF
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '(\h*,\h*)', ', ')
ConsoleWrite('After1 -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '(\h*\v+\h*,\h*)', ', ' & @CRLF)
ConsoleWrite('After2 -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
Задача:
В тексте:
Код
Иванов Николай Иванович 15 июня 1965г. город Волгоград холост; Васильев Иван Васильевич 16 ноября 1960г. город Москва женат; Николаев Василий Николаевич 20 декабря 1962г. деревня Дубовка женат;
сократить имя и отчество до инициала с точкой и поставить их перед фамилией.
Решение:
Можно воспользоваться тем, что ФИО записано после начала строки или ";" и перед цифрами. Но мы "зацепимся" за заглавные буквы в ФИО, ведь в тексте больше нет других трех подряд идущих слов, начинающихся с прописной буквы, кроме ФИО.
1. Описываем фамилию:
([Ё-Я]\S+\s)
Расшифровка:
"[Ё-Я]" - одна заглавная русская буква
"\S+" - 1 или более непробельный символов
"\s" - один пробел
всё заключено в группу с захватом, для формирования обратной ссылки
2. Описываем имя и отчество:
([Ё-Я])\S+\s
Шаблон отличается только расположение группы с захватом - здесь она захватывает только первый символ.
3. Итоговый шаблон:
([Ё-Я]\S+\s)([Ё-Я])\S+\s([Ё-Я])\S+\s
Обратные ссылки будут соответствовать:
1 - фамилия
2 - первая буква имени
3 - первая буква отчества
отсюда получаем нужный нам формат замены:
$2.$3.$1
Код
$sText = 'Иванов Николай Иванович 15 июня 1965г. город Волгоград холост; Васильев Иван Васильевич 16 ноября 1960г. город Москва женат; Николаев Василий Николаевич 20 декабря 1962г. деревня Дубовка женат;'
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '([Ё-Я]\S+\s)([Ё-Я])\S+\s([Ё-Я])\S+\s', '$2.$3.$1')
ConsoleWrite('After --------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
ConsoleWrite('Before -------------' & @CRLF)
ConsoleWrite($sText & @CRLF)
$sText = StringRegExpReplace($sText, '([Ё-Я]\S+\s)([Ё-Я])\S+\s([Ё-Я])\S+\s', '$2.$3.$1')
ConsoleWrite('After --------------' & @CRLF)
ConsoleWrite($sText & @CRLF)