Галопом по основам regex

Скобочные группы ― ()

a(bc)       создаём группу со значением bc -> тестa(?:bc)*    оперетор ?: отключает группу -> тестa(?<foo>bc) так, мы можем присвоить имя группе -> тест

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

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

Задачки (пока без картинок)

  • На вход скрипта дан введенный пользователем номер телефона в
    виде 8-911-404-44-11 или +7(812)6786767 (в начале 8 или +7, потом идут 10 цифр и, возможно, какие-то символы).
    То есть, как и в прошлой задаче, человек вводит номер как хочет.
    Надо проверить номер на правильность и привести любой номер к единому формату 89114044411
    (то есть, заменить +7 на 8 и выкинуть весь мусор вроде пробелов, скобок и минусов, кроме цифр)
  • Автозамена. Напиши скрипт, заменяющий определенное слово на другое (например, слово
    «дурак» на «хороший человек» в фразе «ты дурак»). Скрипт должен не пропускать слово,
    если оно написано буквами в разном регистре (ДуРАк), с заменой русских букв
    на похожие английские (а -> a), или через пробелы («ты — д у р а к»)
  • Дан текст, содержащий в себе email’ы (адреса почты вроде you+me@some.domain-domain.com ). Напиши
    скрипт, выводящий все email, встречающиеся в этом тексте
  • «Grammar Nazi». Напиши скрипт, проверяющий текст на наличие злостных ошибок:
    • нет пробела после запятой, точки с запятой, восклицательного знака,
      вопросительного знака, двоеточия
    • «жи» или «ши» написано с буквой ы
    • в тексте есть слово «координально» или «сдесь», «зделал», «зделаю», «зделан»
    • в тексте есть слова «а» или «но» без запятой перед ними.
    • (можешь добавить еще несколько правил, если хорошо знаешь русский язык)

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

  • Если ты сделал задачу про Grammar Nazi, сделай скрипт, которы вместо сообщения об ошибках будет
    молча их исправлять.

PHP regex dot metacharacter

The (dot) metacharacter stands for any single character in the text.

single.php

<?php

$words = ;
$pattern = "/.even/";

foreach ($words as $word) {

    if (preg_match($pattern, $word)) {
        echo "$word matches the pattern\n";
    } else {
        echo "$word does not match the pattern\n";
    }
}

In the array, we have five words.

$pattern = "/.even/";

Here we define the search pattern. The pattern is a string. The regular expression
is placed within delimiters. The delimiters are mandatory.
In our case, we use forward slashes as delimiters. Note that we
can use different delimiters if we want. The dot character stands for any single character.

if (preg_match($pattern, $word)) {
    echo "$word matches the pattern\n";
} else {
    echo "$word does not match the pattern\n";
}

We test all five words if they match with the pattern.

$ php single.php 
Seven matches the pattern
even does not match the pattern
Maven does not match the pattern
Amen does not match the pattern
Leven matches the pattern

The Seven and Leven words match our search pattern.

Escape-знаки

Обратная косая черта (\) в регулярных выражениях указывает, что следующий за ней символ либо является специальным знаком (как показано в следующей таблице), либо должен интерпретироваться буквально. Дополнительные сведения см. в разделе Escape-символы.

Escape-символ Описание Шаблон Число соответствий
Соответствует знаку колокольчика, \u0007. в
В классе символов соответствует знаку BACKSPACE, \u0008. в
Соответствует знаку табуляции, \u0009. , в
Соответствует знаку возврата каретки, \u000D. ( не эквивалентен знаку начала новой строки, .) в
Соответствует знаку вертикальной табуляции, \u000B. в
Соответствует знаку перевода страницы, \u000C. в
Соответствует знаку новой строки, \u000A. в
Соответствует escape-знаку, \u001B. в
nnn Использует восьмеричное представление для указания символа (nnn состоит из двух или трех цифр). , в
nn Использует шестнадцатеричное представление для указания символа (nn состоит ровно из двух цифр). , в
Xx Соответствует управляющему символу ASCII, который задан как X или x, где X или x является буквой управляющего символа. в (Ctrl-C)
nnnn Совпадение со знаком Юникода в шестнадцатеричном представлении (строго четыре цифры, представленные как nnnn). , в
Если за этим знаком следует символ, не распознанный как escape-символ из этой и других таблиц данной темы, то соответствует в точности этому символу. Например, — это то же самое, что и , а — то же самое, что и . Это позволяет обработчику регулярных выражений распознавать языковые элементы (такие как *или ?) и символьные литералы (представленные как или ). и в

Метасимволы

В регулярных выражениях используются два типа символов: обычные символы и метасимволы. Обычные символы — это те символы, которые имеют «буквальное» значение, а метасимволы — это те символы, которые имеют «особое» значение в регулярном выражении.

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

Одним из основных метасимволов является обратный слэш (\), который меняет тип символа, следующего за ним, на противоположный. Таким образом обычный символ можно превратить в метасимвол, а если это был метасимвол, то он теряет свое специальное значение и становится обычным символом. Этот приём нужен для того, чтобы вставлять в текст специальные символы как обычные. Например, символ в обычном режиме не имеет никаких специальных значений, но — это уже метасимвол, который обозначает: «любая цифра». Символ точка в обычном режиме значит — «любой единичный символ», а экранированная точка (\.) означает просто точку.

Метасимвол Описание пример
. Соответствует любому одиночному символу, кроме новой строки. /./ соответствует строке, состоящей из одного символа.
^ Соответствует началу строки. /^cars/ соответствует любой строке, которая начинается с cars.
$ Соответствует шаблону в конце строки. /com$/ соответствует строке, заканчивающейся на com, например gmail.com
* Соответствует 0 или более вхождений. /com*/ соответствует commute, computer, compromise и т.д.
+ Соответствующий предыдущему символу появляется как минимум один раз. Например, /z+oom/ соответствует zoom.
\ Используется для удаления метасимволов в регулярном выражении. /google\.com/ будет рассматривать точку как буквальное значение, а не как метасимвол.
a-z Соответствует строчным буквам. cars
A-Z Соответствует буквам в верхнем регистре. CARS
0-9 Соответствует любому числу от 0 до 9. /0-5/ соответствует 0, 1, 2, 3, 4, 5
Соответствует классу символов. // соответствует pqr
| Разделяет перечисление альтернативных вариантов. /(cat|dog|fish)/ соответствует cat или dog или fish
\d Любая цифра. /(\d)/ соответствует цифре
\s Найти пробельный символ (в т.ч. табуляция). /(\s)/ соответствует пробелу
\b Граница слова (начало или конец). /\bWORD/ найти совпадение в начале слова

Бекслеши

Если ты смотрел другие учебники по регулярным выражениям, то наверно заметил,
что бекслеш везде пишут по-разному. Где-то пишут один бекслеш:
, а здесь в примерах он повторен 2 раза: .
Почему?

Язык регулярных выражений требует писать бекслеш один раз. Однако в
строках в одиночных и двойных кавычках в PHP бекслеш тоже имеет особое
значение: .
Ну например, если написать то PHP воспримет это как
специальную комбинацию и вставит в строку только символ
(и движок регулярных выражений не узнает о бекслеше перед ним). Чтобы
вставить в строку последовательность , мы должны удвоить бекслеш
и записать код в виде .

По этой причине в некоторых случаях (там, где последовательность символов
имеет специальный смысл в PHP) мы обязаны удваивать бекслеш:

  • Чтобы написать в регулярке , мы пишем в коде
  • Чтобы написать в регулярке , мы удваиваем каждый
    бекслеш и пишем
  • Чтобы написать в регулярке бекслеш и цифру (),
    бекслеш надо удвоить:

В остальных случаях один или два бекслеша дадут один и тот же
результат: и вставят в строку пару
символов — в первом случае 2 бекслеша это последовательность
для вставки бекслеша, во втором случае специальной последовательности
нет и символы вставятся как есть. Проверить, какие символы вставятся в строку,
и что увидит движок регулярных выражений, можно с помощью
echo: . Да, сложно, а что поделать?

PHP PRCE functions

We define some PCRE regex functions. They all have a preg prefix.

  • — splits a string by regex pattern
  • — performs a regex match
  • — search and replace string by regex pattern
  • — returns array entries that match the regex pattern

Next we will have an example for each function.

php> print_r(preg_split("@\s@", "Jane\tKate\nLucy Marion"));
Array
(
     => Jane
     => Kate
     => Lucy
     => Marion
)

We have four names divided by spaces. The is a character
class which stands for spaces. The function returns
the split strings in an array.

php> echo preg_match("##", "s");
1

The function looks if the ‘s’ character
is in the character class . The class stands for all
characters from a to z. It returns 1 for success.

php> echo preg_replace("/Jane/","Beky","I saw Jane. Jane was beautiful.");
I saw Beky. Beky was beautiful.

The function replaces all occurrences of
the word ‘Jane’ for the word ‘Beky’.

php> print_r(preg_grep("#Jane#", ));
Array
(
     => Jane
)

The function returns an array of words that
match the given pattern. In this example, only one word is returned in the array.
This is because by default, the search is case sensitive.

php> print_r(preg_grep("#Jane#i", ));
Array
(
     => Jane
     => jane
     => JANE
)

In this example, we perform a case insensitive grep. We put the
modifier after the right delimiter. The returned array has now three words.

Опечаточники

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

Например, государственные органы, которые хотят провести закупки, обязаны организовать публичные торги и
разместить объявление о них на сайте госзакупок. Чтобы помешать всем желающим участвовать в тендере
(и чтобы отдать заказ «своим людям» и получить потом от них в свой карман часть денег), они заменяют в
описании заказа некоторые русские буквы на похожие на них латинские. Таким образом, не предупрежденные
заранее организации не смогут найти объявление через поиск и принять участие в конкурсе.

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

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

Для проверки работоспособности, попробуй применить программу к тексту из поля «Наименование заказа» на
странице (осторожно, спойлер!)

или

Дополнительная задача: добавь в программу автоматическое исправление найденных «опечаток».

Подсказки для глупеньких:

P.S. На сайте программистских комиксов xkcd есть комикс про регулярные выражения:
перевод, оригинал (англ.).

дальше:
Повторим? →

PHP preg_match() function examples

Let’s take some examples of using the function.

1) Using the PHP preg_match() to match a number

The following example uses the to match a number with one or more digits using the character class:

Output:

Note that the stops searching as soon as it finds a match. In this example, 1995 also matches the pattern . However, the already finds a match with the number 8.

To find all the matches, you need to use the function.

2) Using the PHP preg_match() to match a word character

The following example uses the function to match one or more word characters:

Output:

3) Using the PHP preg_match() with a capturing group example

The following example uses the function to match a number that starts with and is followed by exactly two digits. The pattern also has a capturing group that captures the last two digits:

Output:

The array contains two elements. The first element contains the text that matches the whole pattern, while the second element contains the first capturing group .

The following example uses the same pattern with the additional named capturing group:

Output:

4) Using the PHP preg_match() function with the PREG_OFFSET_CAPTURE flag

Sometimes, you want to find a match in a string and the starting position of the match. To do that, you use the flag. For example:

Output:

In this example, the pattern matches any text with three letters in uppercase. Since we use the flag, it returns the match (PHP) and the starting position (or offset) of the text PHP in the string.

5) Using the preg_match() function with the PREG_UNMATCHED_AS_NULL flag

By default, the function returns an empty string for the unmatched capturing group (or subpattern).

If you want the function to return null instead, you can use the flag.

The following example uses the function without the flag.

Output:

In this example, the string has the text that matches the subpatterns .

However, in the following example, the string doesn’t have a text that matches the subpattern:

Output:

The string doesn’t have any text that matches the subpattern, the returns an empty string.

Since we use the flag, the function returns null for the unmatched subpattern instead.

The following example uses the flag. So it returns instead of an empty string for the unmatched subpattern:

Output:

6) Using the php preg_match() with the offset parameter

Suppose that you have the following string:

If you use the , it’ll match the first number, which is 1.

However, if you pass an offset parameter that specifies the starting position to search, it’ll match the second number :

Output:

In this example, the function starts searching for matches from position ten instead of 0.

Notice that the pattern may contain assertions like , , or . Therefore, the offset is not equivalent to passing the substring to the function.

Описание

preg_match_all

Ищет в строке subject все совпадения с шаблоном

pattern и помещает результат в массив

matches в порядке, определяемом комбинацией флагов

flags.

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

не с начала строки, а от конца последнего найденного вхождения.

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

(необходимо понимать, что использование PREG_PATTERN_ORDER одновременно с PREG_SET_ORDER бессмысленно):

PREG_PATTERN_ORDER

Если этот флаг установлен, результат будет упорядочен следующим образом:

элемент $matches содержит массив полных вхождений шаблона,

элемент $matches содержит массив вхождений первой подмаски, и так далее.

Результат работы примера:

<b>example: </b>, <div align=left>this is a test</div>

example: , this is a test

Как мы видим, $out содержит массив полных вхождений шаблона,

а элемент $out содержит массив подстрок, содержащихся в тегах.

PREG_SET_ORDER

Если этот флаг установлен, результат будет упорядочен следующим образом:

элемент $matches содержит первый набор вхождений,

элемент $matches содержит второй набор вхождений, и так далее.

Результат работы примера:

<b>example: </b>, example: 

<div align="left">this is a test</div>, this is a test

В таком случае массив $matches содержит первый набор вхождений, а именно:

элемент $matches содержит первое вхождение всего шаблона,

элемент $matches содержит первое вхождение первой подмаски, и так далее.

Аналогично массив $matches содержит второй набор вхождений, и так для каждого найденного набора.

PREG_OFFSET_CAPTURE

В случае, если этот флаг указан, для каждой найденной подстроки будет указана

ее позиция в исходной строке. Необходимо помнить, что этот флаг меняет

формат возвращаемых данных: каждое вхождение возвращается в виде массива,

в нулевом элементе которого содержится найденная подстрока, а в первом — смещение.

Данный флаг доступен в PHP 4.3.0 и выше.

В случае, если никакой флаг не используется, по умолчанию используется

PREG_PATTERN_ORDER.

Поиск осуществляется слева направо, с начала строки. Дополнительный параметр

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

начальной позиции для поиска. Дополнительный параметр

offset доступен, начиная с PHP 4.3.3.

Возвращает количество найденных вхождений шаблона (может быть нулем) либо

FALSE, если во время выполнения возникли какие-либо ошибки.

Пример 1. Получение всех телефонных номеров из текста.

Пример 2. Жадный поиск совпадений с HTML-тэгами

Результат работы примера:

matched: <b>bold text</b>

part 1: <b>

part 2: bold text

part 3: </b>



matched: <a href=howdy.html>click me</a>

part 1: <a href=howdy.html>

part 2: click me

part 3: </a>

PHP regex exact word match

In the following examples we show how to look for exact word matches.

php> echo preg_match("/mother/", "mother");
1
php> echo preg_match("/mother/", "motherboard");
1
php> echo preg_match("/mother/", "motherland");
1

The pattern fits the words mother, motherboard and motherland.
Say, we want to look just for exact word matches. We will use the aforementioned
anchor and characters.

php> echo preg_match("/^mother$/", "motherland");
0
php> echo preg_match("/^mother$/", "Who is your mother?");
0
php> echo preg_match("/^mother$/", "mother");
1

Using the anchor characters, we get an exact word match for a pattern.

Примеры

Следующий скрипт использует метод экземпляра строки для сопоставления с именем в формате имя фамилия и выводит его в формате фамилия, имя. В тесте замены скрипт использует заменители и , которые заменяются на результаты соответствующих сопоставившихся подгрупп регулярного выражения.

Пример выведет «Smith, John» и «Смит, Джон»

Символы конца строки различаются на различных платформах (Unix, Windows и так далее). Разбиение строк из этого примера работает на всех платформах.

Обратите внимание, что порядок шаблонов в регулярном выражении имеет значение. Этот пример демонстрирует, как можно использовать флаг «липучести» регулярных выражений для сопоставления с отдельными строками многострочного ввода

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

Во время выполнения можно проверить, поддерживается ли флаг «липучести», при помощи блока . Для этого надо использовать либо выражение с , либо конструктор (поскольку нотация обрабатывается во время компиляции, исключение будет выброшено до того, как выполнение достигнет блока ). Например:

Как уже сказано выше, символьные классы и сопоставляются только с базовыми символами ASCII; то есть, с символами от «a» до «z», от «A» до «Z», от «0» до «9» и символом «_». Для сопоставления с символами из других языков, например, с кириллическими или иврита, используйте форму , где «hhhh» — это значение символа Юникода, записанное в шестнадцатеричной форме. Этот пример демонстрирует, как можно выделить символы Юникода, составляющие слова.

Вот на этом внешнем ресурсе можно составить полный диапазон блоков Юникода для различных письменностей: regexp-unicode-block.

Альтернативы¶

Выражения в списке альтернатив разделяются .

Таким образом, будет соответствовать любому из , или (также как и ).

Первое выражение включает в себя все от последнего разделителя шаблона (, или начало шаблона) до первого , а последнее выражение содержит все от последнего к следующему разделителю шаблона.

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

Выражения в списке альтернатив пробуются слева направо, принимается первое же совпадение.

Например, регулярное выражение в строке будет соответствовать — первое же совпадение.

Также помните, что в квадратных скобках воспринимается просто как символ, поэтому, если вы напишите , это тоже самое что .

Модификаторы регулярных выражений

Модификаторы указываются либо в скобках, например так: (?Ui), либо после закрывающего символа ‘/pattern/Ui’.

Модификатор Описание
i Выполняет поиск без учета регистра. Например «/a/i» ищет и a, и A.
m Выполняет многострочный поиск (шаблоны, которые ищут начало или конец строки, будут соответствовать началу или концу каждой строки)
u Обеспечивает правильное сопоставление шаблонов в кодировке UTF-8 (для поиска русского текста например).
U Инвертирует «жадность» (по умолчанию жадный, т.е. пытается захватить как можно большую строку, подходящую по условию).
s Если используется, то символ точка (.) соответствует и переводу строки. Иначе она ему не соответствует.
x Игнорировать пробелы. В этом случае пробелы нужно экранировать обратным слэшем \.

При использовании модификаторов, можно использовать знак минус для отключения модификатора. Например: (?m-i) — включаем многострочный поиск и отключаем регистронезависимый.

Строковые методы, поиск и замена

Следующие методы работают с регулярными выражениями из строк.

Все методы, кроме replace, можно вызывать как с объектами типа regexp в аргументах, так и со строками, которые автоматом преобразуются в объекты RegExp.

Так что вызовы эквивалентны:

var i = str.search(/\s/)
var i = str.search("\\s")

При использовании кавычек нужно дублировать \ и нет возможности указать флаги. Если регулярное выражение уже задано строкой, то бывает удобна и полная форма

var regText = "\\s"
var i = str.search(new RegExp(regText, "g"))

Возвращает индекс регулярного выражения в строке, или -1.

Если Вы хотите знать, подходит ли строка под регулярное выражение, используйте метод (аналогично RegExp-методы ). Чтобы получить больше информации, используйте более медленный метод (аналогичный методу ).

Этот пример выводит сообщение, в зависимости от того, подходит ли строка под регулярное выражение.

function testinput(re, str){
   if (str.search(re) != -1)
      midstring = " contains ";
   else
      midstring = " does not contain ";
   document.write (str + midstring + re.source);
}

Если в regexp нет флага , то возвращает тот же результат, что .

Если в regexp есть флаг , то возвращает массив со всеми совпадениями.

Чтобы просто узнать, подходит ли строка под регулярное выражение , используйте .

Если Вы хотите получить первый результат — попробуйте r.

В следующем примере используется, чтобы найти «Chapter», за которой следует 1 или более цифр, а затем цифры, разделенные точкой. В регулярном выражении есть флаг , так что регистр будет игнорироваться.

str = "For more information, see Chapter 3.4.5.1";
re = /chapter (\d+(\.\d)*)/i;
found = str.match(re);
alert(found);

Скрипт выдаст массив из совпадений:

  • Chapter 3.4.5.1 — полностью совпавшая строка
  • 3.4.5.1 — первая скобка
  • .1 — внутренняя скобка

Следующий пример демонстрирует использование флагов глобального и регистронезависимого поиска с . Будут найдены все буквы от А до Е и от а до е, каждая — в отдельном элементе массива.

var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var regexp = //gi;
var matches = str.match(regexp);
document.write(matches);

// matches = 

Метод replace может заменять вхождения регулярного выражения не только на строку, но и на результат выполнения функции. Его полный синтаксис — такой:

var newString = str.replace(regexp/substr, newSubStr/function)
Объект RegExp. Его вхождения будут заменены на значение, которое вернет параметр номер 2
Строка, которая будет заменена на .
Строка, которая заменяет подстроку из аргумента номер 1.
Функция, которая может быть вызвана для генерации новой подстроки (чтобы подставить ее вместо подстроки, полученной из аргумента 1).

Метод не меняет строку, на которой вызван, а просто возвращает новую, измененную строку.

Чтобы осуществить глобальную замену, включите в регулярное выражение флаг .

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

var ab = "a b".replace("\\s","..") // = "a b"

Вызов replace оставил строку без изменения, т.к искал не регулярное выражение , а строку «\s».

В строке замены могут быть такие спецсимволы:

Pattern Inserts
Вставляет «$».
Вставляет найденную подстроку.
Вставляет часть строки, которая предшествует найденному вхождению.
Вставляет часть строки, которая идет после найденного вхождения.
or Где или — десятичные цифры, вставляет подстроку вхождения, запомненную -й вложенной скобкой, если первый аргумент — объект RegExp.

Если Вы указываете вторым параметром функцию, то она выполняется при каждом совпадении.

В функции можно динамически генерировать и возвращать строку подстановки.

Первый параметр функции — найденная подстрока. Если первым аргументом является объект , то следующие параметров содержат совпадения из вложенных скобок. Последние два параметра — позиция в строке, на которой произошло совпадение и сама строка.

Например, следующий вызов возвратит XXzzzz — XX , zzzz.

function replacer(str, p1, p2, offset, s)
{
return str + " - " + p1 + " , " + p2;
}
var newString = "XXzzzz".replace(/(X*)(z*)/, replacer)

Как видите, тут две скобки в регулярном выражении, и потому в функции два параметра , .
Если бы были три скобки, то в функцию пришлось бы добавить параметр .

Следующая функция заменяет слова типа на :

function styleHyphenFormat(propertyName)
{
  function upperToHyphenLower(match)
  {
    return '-' + match.toLowerCase();
  }
  return propertyName.replace(//, upperToHyphenLower);
}

PHP regex alternation

The next example explains the alternation operator . This operator
enables to create a regular expression with several choices.

alternation.php

<?php

$names = ;

$pattern = "/Jane|Beky|Robert/";

foreach ($names as $name) {

    if (preg_match($pattern, $name)) {
        echo "$name is my friend\n";
    } else {
        echo "$name is not my friend\n";
    }
}

We have eight names in the array.

$pattern = "/Jane|Beky|Robert/";

This is the search pattern. The pattern looks for ‘Jane’, ‘Beky’, or
‘Robert’ strings.

$ php alternation.php 
Jane is my friend
Thomas is not my friend
Robert is my friend
Lucy is not my friend
Beky is my friend
John is not my friend
Peter is not my friend
Andy is not my friend

This is the output of the script.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector