Примеры регулярных выражений на PHP

Добрый день. Устраивался я на работу программистом на удаленке. Мне прислали тест для проверки моих проф. знаний. Мне требовалось решить 18 задач и отправить результат работы обратно по почте.

Пока решал тест пришлось пару задач я пропустить. В них я не до конца понимал, что требуется.

Итог — я не прошел тест, мне сказали, что у меня слабые знания регулярных выражений.

Если кому-то пригодится моя работа буду рад.

Если что-то не понятно, пишите комменты.

1. Дан набор чисел. Необходимо найти в нём все числа меньше 4.
Пример: 1 0 2 9 3 8 4 7 5 6 8 9 10 11 -1 -65 432 3 74
Здесь при решении я не использовал регулярные выражения

[php] $txt = ‘1 0 2 9 3 8 4 7 5 6 8 9 10 11 -1 -65 432 3 74’;
$var_txt = explode(" ", $txt);

foreach ($var_txt as $key => $value)
{
if ($value < 4)
echo ‘ , ‘.$value.’ ‘;
}
//Решение: , 1 , 0 , 2 , 3 , -1 , -65 , 3
[/php]

2. Дана строка произвольной длины. В строке перечислены разнообразные символы, буквы разных алфавитов и прочее. Необходимо получить все буквы русского алфавита, а также все числа от 0 до 6.
Пример: 4504569ук432534345345890456.43=3503245axc4521kdx230k023то94о289076с2

[php] $str = ‘4504569ук432534345345890456.43=3503245axc4521kdx230k023то94о289076с2’;

$str = iconv(‘windows-1251′,’utf-8’,$str); // у меня не понимал русские пока не преобразовал. Работал в денвере WIN7x64

preg_match_all("/[0-6А-Яа-я]/",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
echo ‘ , ‘.$value;
}

//результат
//Решение: , 4 , 5 , 0 , 4 , 5 , 6 , С , Р , 4 , 3 , 2 , 0 , 4 , 5 , 6 , 4 , 3 , 3 , 2 , 4 , 5 , 4 , 5 , 2 , 1 , 2 , 3 , 0 , 0 , 2 , 3 , С , Р , 4 , Р , 2 , 0 , 6 , С , 2
[/php]

3. Дана строка произвольной длины, состоящая из одинаковых символов. Требуется написать два рег. выражения, которые бы возвращали первый символ и всю строку, соответственно.
Пример: «11111111111111».

[php] $str = ‘11111111111111’;

preg_match("/.{1}/",$str, $res);

echo ‘ Первый символ: ‘.$res[0];

preg_match("/.*/",$str, $res);

echo ‘ Вся строка: ‘.$res[0];
[/php]
4. Дана строка «a1 b3 a8 c2 a9 d7 a4 e5 a3 f8 a0 g1».
Требуется написать ОДНО регулярное выражение, которое бы сматчило только числа согласно следующему условию: если перед числом стоит буква «a», то это число должно быть меньше 5, иначе – больше либо равно 5.

НЕ РЕШЕНО

5. Дана произвольная html-страница, необходимо получить содержимое всех тегов div, внутри которых находится минимум 5 подряд идущих цифр.

[php] //Например: "
<div>asd 764 1234457 абвы</div>
<div>asd абвы</div>
<div>asd 764 1257 абвы</div>

".

$str = ‘
<div>asd 764 1234457 абвы</div>
<div>asd абвы</div>
<div>asd 764 1257 абвы</div>

‘;

preg_match_all("!
<div>(.*?[0-9]{5}.*?)</div>

!",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
echo ‘ , ‘.$value;
}

//Решение: , asd 764 1234457 абвы
[/php]

6. Дан текст. Необходимо найти в нём все слова, состоящие из 5 букв.
Пример текста: «дождь лопата два школа арбуз стройка пять дом голова бутан город шпала».

[php] $str = ‘дождь лопата два школа арбуз стройка пять дом голова бутан город шпала’;

//$str = iconv(‘windows-1251′,’utf-8’,$str);

$str = ‘ ‘.$str.’ ‘; //Добавил пробелы

$str = str_replace(" ", " ", $str);

preg_match_all("/\s([а-я]{5})\s/",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
echo ‘ , ‘.$value;
}

/*
Решение: , дождь , школа , арбуз , бутан , город , шпала
*/
[/php]

7. Дано множество строк (каждая строка – с новой строки), состоящих из чисел, разделённых пробелом. Необходимо найти все строки, в которых 5-е число было бы таким же, как и 18-е, а также являлось бы чётным числом и было больше 9.

[php] //имеем набор чисел 1-15 в виде нескольких строк

$str = ’10 12 6 14 10 4 7 3 4 10 10 7 1 11 11 2 14 10 14 8 8 15 2 7 14 9 12 13 15 2
11 8 7 7 12 4 3 7 3 2 8 3 5 6 1 6 12 2 14 5 12 14 6 3 4 8 5 15 10 13
12 6 13 1 10 2 14 3 13 7 5 9 2 5 3 14 8 10 2 13 8 5 8 11 2 11 9 15 6 5
14 2 6 15 12 7 6 7 2 5 1 9 13 2 9 15 2 10 12 14 4 6 15 2 6 10 14 10 14 13
2 7 10 5 15 7 3 6 9 7 7 4 14 9 7 15 6 1 11 4 10 2 1 7 4 9 14 11 1 2
8 6 13 1 5 10 8 14 7 10 3 6 7 14 11 4 10 2 4 2 1 2 1 5 9 13 15 6 15 14
‘;

//получил все строки
preg_match_all ("/(.*?)\n/", $str,$res);

foreach ($res[0] as $value)
{
//разбиваю строку на числа
preg_match_all ("/\s?[0-9]*\s/", $value,$num_array);

$var5 = (int)$num_array[0][4];
$var18 = (int)$num_array[0][17];

//строка, в которой 5-е число такоеже как и 18-е, и больше 9 и оно четное
if ($var5 == $var18 and $var5 > 9 and ($var5%2)==0)
{
echo ‘
‘.$value;
}
}
//результат работы
/*

10 12 6 14 10 4 7 3 4 10 10 7 1 11 11 2 14 10 14 8 8 15 2 7 14 9 12 13 15 2

12 6 13 1 10 2 14 3 13 7 5 9 2 5 3 14 8 10 2 13 8 5 8 11 2 11 9 15 6 5
*/

[/php]

8. Дан текст. Необходимо найти в нём все слова, содержащие букву «а».
Пример текста: «дождь лопата два школа арбуз стройка пять дом голова бутан город шпала».

[php] $str = ‘дождь лопата два школа арбуз стройка пять дом голова бутан город шпала’;

preg_match_all("/\s*[а-я]*\s?/",$str, $res); //нашел все слова в строке

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
if (strrpos($value, ‘а’) == true) // ищем букву

echo ‘ , ‘.$value;
}

/*
Решение: , лопата , два , школа , стройка , голова , бутан , шпала
*/
[/php]

9. Дана строка, содержащая имя человека, и дано регулярное выражение: «/(?#Имя)[А-Я][а-я]+\s(?#Отчество)[А-Яа-я]+\s(?#Фамилия)(?:[а-я]+)/». Необходимо изменить последнюю подмаску (следующую за комментарием «Фамилия») так, чтобы регулярное выражение сработало и вернуло бы всю строку (изменять или добавлять символьные классы нельзя).

Пример имени: «Иван Семенович Петров».

[php] echo ‘
Решение: "/(?#Имя)[А-Я][а-я]+\s(?#Отчество)[А-Яа-я]+\s(?#Фамилия)(?[а-я]+)/" ‘;
[/php]

10. Дан текст. Требуется написать регулярное выражение, которое бы матчило все строки, НЕ начинающиеся с числа «2».

[php] //Пример текста:
1 http://www.yandex.ru
2 http://lenta.ru
3 www.google.com
02 facebook.com
36 twitter.com
12 www.imdb.com
1 blizzard.com
2 http://kinopoisk.ru
21 ozon.ru
0029 http://www.bicotender.ru’;
[/php]

НЕ РЕШЕНО

11. Дан набор тегов, необходимо получить содержимое всех тегов div, которые НЕ вложены в другие теги div. Учесть, что в тег div может быть вложено неограниченное количество других тегов div (рекурсивно) – требуется получить всё содержимое самого внешнего тега div.

Пример текста:
[html] <div>Блок1</div>
<div style="display:none;">Блок2</div>
<div><h1>Заголовок</h1>Блок3</div>
<table>
<tr><td>
<div>Вложенный
<div>блок
<div>4</div>
</div>
и ещё чуть-чуть.
</div>
</td>
</tr>
</table>’;
[/html] [php] //Решить можно было бы используя http://simplehtmldom.sourceforge.net/
//подгружаем библиотеку
//require_once ‘library/simplehtmldom.php’;
//создаём новый объект
//$html = new simple_html_dom();
//загружаем в него данные
//$html = file_get_html($str2);
//Ищем все
<div>

//$ret = $html->find(‘div’);
//пример можно глянуть тут http://web2033.com/parsing-php-simple-html-dom/
//но я использовал свой алгоритм + регулярные выражения

// исходная строка из задания для работы
$str2 = ‘
<div>Блок1</div>
<div style="display:none;">Блок2</div>
<div>
<h1>Заголовок</h1>
блока3</div>
<table>
<tr>
<td>
<div>
Вложенный
<div>
блок
<div>4</div>
</div>
и ещё чуть-чуть.</div>
</td>
</tr>
</table>’;

//echo $str2;

$str2 = str_replace(" style=\"display:none;\"", "",$str2); //убираю стиль

// находим все дивы
preg_match_all("/
<div>
/",$str2, $res);

$id = 0; // количество блоков div
$pos = 0; // позиция

//пронумеруем их <div1> <div2> и т.д. но закрывающие теги не трогаем
foreach ($res[0] as $value)
{
$id++;
$pos = strpos($str2,’
<div>
‘); // смотрю позицию где тег в строке
$str2 = substr_replace($str2,'<div’.$id.’>’,$pos,5); // вставляю на его место тег с номером
}

//echo $str2;

// ЗАДАЧА необходимо получить содержимое всех тегов
//<div>
//, которые НЕ вложены в другие теги
//<div>
// все просто надо найти дивы по номерам <div1..> и содержимым в котором нет других тегов DIV. Закрываются они также тегом </div>

for ($i = 1; $i <= $id; $i++){

preg_match_all("!<div".$i.">.*?</div>

!",$str2, $res);

foreach ($res[0] as $value)
{
$count = substr_count ($value,'<div’); //смотрю сколько div у нас есть. Если 1 то нет вложенных

if ($count == 1)

echo ‘ , ‘.$value;

}
}
//Результат работы: <div1>Блок1</div>

, <div2>Блок2</div>

, <div3>

<h1>Заголовок</h1>

блока3</div>

, <div6>4</div>

// ЗАДАЧА требуется получить всё содержимое самого внешнего тега
//<div>. Я так понимаю это Див в котором Максимальное количество вложенных DIV
// если нет, то я не верно решил

$counter = 0; // для запоминания макс количества
$number = 0; // номер тега с максимальным вложением тегов

for ($i = 1; $i <= $id; $i++){
preg_match_all("!<div".$i.">.*?</div>

*?.*?</div>

*?.*?!",$str2, $res);
foreach ($res[0] as $value)
{
$count = substr_count ($value,'<div’); //смотрю сколько div у нас есть. Если 1 то нет вложенных

if ($counter<=$count)
{
$counter = $count;
$number = $i;
}
}
}
echo ‘Div с номером ‘.$number.’ имеет ‘.($counter-1).’ вложенных Div’;
//Div с номером 4 имеет 2 вложенных Div
//
<div>
Вложенный
<div>
блок
<div>4</div>
</div>

и ещё чуть-чуть.</div>

//Ну и выведем его на экран
preg_match_all("!<div".$number.">.*?</div>

*?.*?</div>

*?.*?!",$str2, $res);
echo ‘
‘.$res[0][0];

//Можно было конечно удалить все лишние теги по краям, но я оставил для наглядности
[/php]

12. Дана html страница сблоками:

Блок 1

Внутренний блок 1

Блок 2

Какой-то текст 2

Какой-то текст 3

Блок 3

Внутренний блок 3

Требуется получить содержимое всех блоков, внутри которых нет других блоков div.
Регулярное выражение должно отрабатывать быстро даже при очень большой вложенности тегов.’;
[php] $str2 =’ //строка с html кодом
<table>
<tbody>
<tr>
<td>
<div>
<h1>Блок 1</h1>
<div>Внутренний блок 1</div>
</div></td>
<td>
<div>
<h1>Блок 2</h1>
Какой-то текст 2

</div></td>
</tr>
<tr>
<td>
<div>

Какой-то текст 3
<h1>Блок 3</h1>
<div><strong>Внутренний блок</strong> 3</div>
</div></td>
</tr>
</tbody>
</table>
‘;

// находим все дивы
preg_match_all("/
<div>

/",$str2, $res);

$id = 0; // количество блоков div
$pos = 0; // позиция

//пронумеруем их и т.д. но закрывающие теги не трогаем
foreach ($res[0] as $value)
{
$id++;
$pos = strpos($str2,’
<div>’); // смотрю позицию где тег в строке
$str2 = substr_replace($str2,’&lt;div’.$id.’&gt;’,$pos,5); // вставляю на его место тег с номером
}//echo $str2;
// ищу div без вложений
for ($i = 1; $i &lt;= $id; $i++){

preg_match_all("!&lt;div".$i."&gt;.*?

</div>
!",$str2, $res);

foreach ($res[0] as $value)
{
$count = substr_count ($value,’&lt;div’); //смотрю сколько div у нас есть. Если 1 то нет вложенных

if ($count == 1)
echo ‘ , ‘.$value;

}
}
//результат работы
//Внутренний блок 1

</div>
, <strong>Внутренний блок</strong> 3

</div>
//также div`ы не вырезал для наглядности результата
[/php]

13. Дан текст. Необходимо найти в нём все слова, состоящие из 5 букв и содержащие букву «а».
Пример текста: «дождь лопата два школа арбуз стройка пять дом голова бутан город шпала»‘;

[php] $str = ‘дождь лопата два школа арбуз стройка пять дом голова бутан город шпала’;

$str = ‘ ‘.$str.’ ‘; //Добавил пробелы

$str = str_replace(" ", " ", $str);

preg_match_all("/\s([а-я]{5})\s/",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
if (strrpos($value, ‘а’) == true) // ищем букву
echo ‘ , ‘.$value;
}

//Решение: , школа , арбуз , бутан , шпала
[/php]

14. Дан текст. Необходимо найти все предложения, в которых НЕ встречается слово «два». Предложения разделены точками. Точка используется исключительно как знак окончания предложения. Все предложения начинаются с заглавной буквы и больше заглавных букв в себе не содержат.

Пример текста:
Два на два – четыре. Три на три – девять. Два на четыре – восемь. Четыре на пять – двадцать. Восемь на два – шестнадцать. Семь на восемь – пятьдесят шесть. Шесть на четыре – двадцать четыре. Пять на два – десять.

[php] $str = ‘Два на два – четыре. Три на три – девять. Два на четыре – восемь. Четыре на пять – двадцать. Восемь на два – шестнадцать. Семь на восемь – пятьдесят шесть. Шесть на четыре – двадцать четыре. Пять на два – десять.’;

preg_match_all("/([А-Я])(.*?)\./",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
echo ‘
‘.$value;
}
/*
Решение:
Два на два – четыре.
Три на три – девять.
Два на четыре – восемь.
Четыре на пять – двадцать.
Восемь на два – шестнадцать.
Семь на восемь – пятьдесят шесть.
Шесть на четыре – двадцать четыре.
Пять на два – десять.
*/
[/php]

15. Дан html. Необходимо получить содержимое всех тегов «P», которые находятся в закомментированных блоках.
[php] //готовим данные
$str = ‘
Комментарий в html коде
<!—

комментарий .

еще один.

—>
<!—

коммент 3 .

четвертый 4.

—>

‘;
//данный пример работает если комментарий умещен в одну строку
//получаем комментарии
preg_match_all("/<!—(.*?)—>/",$str, $res);
$p = »;
foreach ($res[0] as $value)
{
//получаем содержимое тега P
preg_match_all("!

(.*?)

!",$value, $p);
foreach ($p[0] as $teg_p)
{
echo ‘
‘.strip_tags($teg_p, »);
}
}

/*
РЕШЕНИЕ:

комментарий .
еще один.
коммент 3 .
четвертый 4.
*/
[/php]

16. Дан SQL-запрос SELECT с непредсказуемым форматированием, но валидный. Получить в одну строку список всех столбцов, выбираемых запросом (звездочку преобразовывать в имена не нужно: все равно не получится). Учесть, что в именах столбцов могут быть такие вещи, как from, join, `inner join` и даже `from from from join cross outer from`’;
надо найти все что между select и последним словом FROM.
как правила имена задаются ковычками рядом с выбираемым столбцом, но и столбец может быть c ковычками, также между ними ОБЯЗАН быть пробел.

[php] //пример запроса SELECT f1 `from`, `f2` `join`, f3 `inner join`, f4 `from from from join cross outer from` FROM users;

$str = "SELECT f1 `from`,`f2` `join`,f3 `inner join`,f4 `from from from join cross outer from` FROM users;";

//$str = str_replace(" `", "

", $str);

//echo ‘
‘.$str;

preg_match_all("/(^`.*?`)?\s`(.*?)`/",$str, $res);

foreach ($res[0] as $value)
{
echo ‘
‘.$value;
}
/*результат работы
`from`
`join`
`inner join`
`from from from join cross outer from`
*/
[/php]

17. Дан html с множеством тегов. Требуется проверить, имеет ли каждый тег соответствующую закрывающуюся пару либо, если тег одиночный, оканчивается ли он на «/>». Html-комментарии, а также конструкции вида 123”> можно не учитывать.
[php] // проверять будем
<div></div>
<h1></h1>
т.е. теги без классов
// решить данную задачу можно разными способами. Я выбрал самый простой. Так как у каждого тега должен быть закрывающий
// я решил посчитать количество тегов открывающих и закрывающих. Их должно быть одинаковое количество. Если есть расхождения значит тег либо не открыт, либо не закрыт.

// возьмем для примера этот текст"
$html =’
<table>
<tbody>
<tr>
<td>
<div>
<h1>Блок 1</h1>
<div>Внутренний блок 1
</div>
</div></td>
<td>
<div>
<h1>Блок 2</h1>
Какой-то текст 2

</div></td>
</tr>
<tr>
<td>
<div>

Какой-то текст 3
<h1>Блок 3</h1>
<div><strong>Внутренний блок</strong> 3</div>
</div></td>
</tr>
</tbody>
</table>
‘;
//найдем все открывающие теги которые есть в коде
preg_match_all("/&lt;([a-zA-Z0-9]*)&gt;/",$html, $res);

//убираю повторения. Для убыстрения работы. Потомучто в массиве $res несколько одних и тех же тегов. Например

$res[0] = array_unique($res[0]);foreach ($res[0] as $value)
{
//посчитаю сколько тегов есть открывающих
$begin_count_teg = substr_count ($html,$value);

//делаю из отквающего тега закрывающий
$value = str_replace("&lt;", " $close_count_teg) //открытых больше чем закрытых
echo ‘
Тег: ‘.$value.’ необходимо проверить он не зарыт’;

}

//результат работы
//Тег:

необходимо проверить либо он не зарыт. И он действительно не закрыт в исходной строке $html.
//
//Проверяю если тег одиночный, оканчивается ли он на «/&gt;»

//снова беру все теги только одиночные например

preg_match_all("/&lt;([a-zA-Z0-9]*)\s/",$html, $res); $res[0] = array_unique($res[0]); // убираю лишние теги foreach ($res[0] as $value) { //найденный тег пробую найти в коде в виде правильно написанного. Если не найду значит не имеет он на концу /&gt;
$count = substr_count ($html,$value.’/&gt;’);
if ($count&lt;1) { echo ‘Тег: ‘.$value.’ /&gt; Не закрыт’;
}
}
// результат работы
//Тег:
Не закрыт

[/php]

18. Дан текст. Требуется ко всем конструкциям вида «(.[\w\d]+)+» присоединить произвольную подстроку. Данная конструкция может быть обрамлена с обеих сторон знаками «%»: в этом случае подстрока должна быть присоединена после первого «%» (перед первой точкой), в остальных случаях подстроку нужно присоединить просто в начало конструкции. Пример текста: «fff .key1.key4.kkk22% %.key2.key4% %.key1 key5 .key6.key7.tumba».
[php] // исходная строка
$str = ‘fff .key1.key4.kkk22% %.key2.key4% %.key1 key5 .key6.key7.tumba’;

// рандомный текст для добавления к знаку процента %
$random_txt = md5( microtime() . mt_rand());

preg_match_all("/(%?.[\w\d]+%?)+/",$str, $res);

echo ‘
Решение: ‘;

foreach ($res[0] as $value)
{
// первое условие
// конструкция может быть обрамлена с обеих сторон знаками «%»: в этом случае подстрока должна быть присоединена после первого «%» (перед первой точкой)

// проверяем обрамлена она % или нет
if ($value[0]==’%’ and substr($value, -1)==’%’){
//подставляем в начало нашу сгенерированную строку
$value = str_replace("%.", ‘%’.$random_txt.".", $value);
}else{
// второе условие
//в остальных случаях подстроку нужно присоединить просто в начало конструкции. Что я и сделал

$value = $random_txt.$value;
}
echo ‘
‘.$value;

}
/*Результат работы

266aad662801151d58dcbdb263481f51fff
266aad662801151d58dcbdb263481f51.key1.key4.kkk22%
%266aad662801151d58dcbdb263481f51.key2.key4%
266aad662801151d58dcbdb263481f51%.key1 key5
266aad662801151d58dcbdb263481f51.key6.key7.tumba

*/

</div>

[/php]
Метки: нет меток

Add a Comment

Your email address will not be published. Required fields are marked *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.