final cleanup regexps

This commit is contained in:
Ilya Kantor 2015-04-07 15:22:06 +03:00
parent 59388d093e
commit 833f7ba70e
132 changed files with 410 additions and 183 deletions

View file

@ -210,13 +210,13 @@ Adobe Flash -- кросс-браузерная платформа для мул
<ul>
<li>Язык [CoffeeScript](http://coffeescript.org/) -- это "синтаксический сахар" поверх JavaScript, он сосредоточен на большей ясности и краткости кода. Как правило, его особенно любят программисты на Ruby.</li>
<li>Язык [TypeScript](http://www.typescriptlang.org/) сосредоточен на добавлении строгой типизации данных, он предназначен для упрощения разработки и поддержки больших систем. Его разрабатывает MicroSoft.</li>
<li>Язык [Dart](https://www.dartlang.org/) предложен компанией Google как замена JavaScript, но другие ведущие интернет-компании объявили о своей незаинтересованности в Dart. Возможно, в будущем он может составить конкуренцию JS.</li>
<li>Язык [Dart](https://www.dartlang.org/) интересен тем, что он не только транслируется в JavaScript, как и другие языки, но и имеет свою независимую среду выполнения, которая даёт ему ряд возможностей и доступна для встраивания в приложения (вне браузера). Он разрабатывается компанией Google.</li>
</ul>
[smart header="ES6 и ES7 прямо сейчас"]
Существуют также трансляторы, которые берут код, использующий возможности будущих стандартов JavaScript, и преобразуют его в более старый вариант, который понимают все браузеры.
Например, [6to5](https://6to5.org/).
Например, [babeljs](https://babeljs.io/).
Благодаря этому, мы можем использовать многие возможности будущего уже сегодня.
[/smart]

View file

@ -268,72 +268,6 @@ function showWarning(width, height, title, contents) {
}
```
### "Именованные аргументы"
*Именованные аргументы* -- альтернативная техника работы с аргументами, которая вообще не использует `arguments`.
Некоторые языки программирования позволяют передать параметры как-то так: `f(width=100, height=200)`, то есть по именам, а что не передано, тех аргументов нет. Это очень удобно в тех случаях, когда аргументов много, сложно запомнить их порядок и большинство вообще не надо передавать, по умолчанию подойдёт.
Такая ситуация часто встречается в компонентах интерфейса. Например, у "меню" может быть масса настроек отображения, которые можно "подкрутить" но обычно нужно передать всего один-два главных параметра, а остальные возьмутся по умолчанию.
В JavaScript для этих целей используется передача аргументов в виде объекта, а в его свойствах мы передаём параметры.
Получается так:
```js
function showWarning(options) {
var width = options.width || 200; // по умолчанию
var height = options.height || 100;
var title = options.title || "Предупреждение";
// ...
}
showWarning({
```
Вызвать такую функцию очень легко. Достаточно передать объект аргументов, указав в нем только нужные:
```js
showWarning({
contents: "Вы вызвали функцию" // и всё понятно!
});
```
Сравним это с передачей аргументов через список:
```js
showWarning(null, null, "Предупреждение!");
// мысль программиста "а что это за null, null в начале? ох, надо глядеть описание функции"
```
Не правда ли, объект -- гораздо проще и понятнее?
Еще один бонус кроме красивой записи -- возможность повторного использования объекта аргументов:
```js
var opts = {
width: 400,
height: 200,
contents: "Текст"
};
showWarning(opts);
opts.contents = "Другой текст";
*!*
showWarning(opts); // вызвать с новым текстом, без копирования других аргументов
*/!*
```
Именованные аргументы применяются во многих JavaScript-фреймворках.
## Устаревшее свойство arguments.callee [#arguments-callee]
[warn header="Используйте NFE вместо `arguments.callee`"]
@ -407,6 +341,72 @@ function f3() {
В учебнике мы это свойство также не будем использовать.
## "Именованные аргументы"
*Именованные аргументы* -- альтернативная техника работы с аргументами, которая вообще не использует `arguments`.
Некоторые языки программирования позволяют передать параметры как-то так: `f(width=100, height=200)`, то есть по именам, а что не передано, тех аргументов нет. Это очень удобно в тех случаях, когда аргументов много, сложно запомнить их порядок и большинство вообще не надо передавать, по умолчанию подойдёт.
Такая ситуация часто встречается в компонентах интерфейса. Например, у "меню" может быть масса настроек отображения, которые можно "подкрутить" но обычно нужно передать всего один-два главных параметра, а остальные возьмутся по умолчанию.
В JavaScript для этих целей используется передача аргументов в виде объекта, а в его свойствах мы передаём параметры.
Получается так:
```js
function showWarning(options) {
var width = options.width || 200; // по умолчанию
var height = options.height || 100;
var title = options.title || "Предупреждение";
// ...
}
showWarning({
```
Вызвать такую функцию очень легко. Достаточно передать объект аргументов, указав в нем только нужные:
```js
showWarning({
contents: "Вы вызвали функцию" // и всё понятно!
});
```
Сравним это с передачей аргументов через список:
```js
showWarning(null, null, "Предупреждение!");
// мысль программиста "а что это за null, null в начале? ох, надо глядеть описание функции"
```
Не правда ли, объект -- гораздо проще и понятнее?
Еще один бонус кроме красивой записи -- возможность повторного использования объекта аргументов:
```js
var opts = {
width: 400,
height: 200,
contents: "Текст"
};
showWarning(opts);
opts.contents = "Другой текст";
*!*
showWarning(opts); // вызвать с новым текстом, без копирования других аргументов
*/!*
```
Именованные аргументы применяются во многих JavaScript-фреймворках.
## Итого
<ul>

View file

@ -354,5 +354,5 @@ function Rabbit() {
...Которой нет в прототипном подходе, потому что в процессе создания `new Rabbit` мы вовсе не обязаны вызывать конструктор родителя. Ведь методы находятся в прототипе.
Поэтому прототипный подход стоит предпочитать функциональному как более быстрый и универсальный. А что касается красоты синтаксиса -- она сильно лучше в новом стандарте ES6, которым можно пользоваться уже сейчас, если взять транслятор [6to5](http://6to5.org/).
Поэтому прототипный подход стоит предпочитать функциональному как более быстрый и универсальный. А что касается красоты синтаксиса -- она сильно лучше в новом стандарте ES6, которым можно пользоваться уже сейчас, если взять транслятор [babeljs](https://babeljs.io/).

View file

@ -10,7 +10,7 @@
<text id="jump:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal">
<tspan x="24" y="175" fill="#8A704D">jump: function</tspan>
<tspan x="131.761719" y="175" fill="#999647"></tspan>
<tspan x="24" y="191" fill="#7ED321">run: function</tspan>
<tspan x="24" y="191" fill="#417505">run: function</tspan>
</text>
<text id="Rabbit.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#8A704D">
<tspan x="13" y="149">Rabbit.prototype</tspan>

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

View file

@ -14,7 +14,7 @@
Но могут быть и другие, например `PropertyError` -- эта ошибка будет возникать, если в прочитанном объекте нет свойства `name` или `age`.
Реализуем её:
Реализуем класс `PropertyError`:
```js
function PropertyError(property) {
@ -34,17 +34,17 @@ function PropertyError(property) {
PropertyError.prototype = Object.create(Error.prototype);
```
Посмотрим внимательнее на код -- в нём важные детали того, как можно позаботиться о стандартных свойствах объекта ошибки:
В этом коде вы можете видеть ряд важных деталей, важных именно для ошибок:
<dl>
<dt>`name` -- имя ошибки.</dt>
<dd>Должно совпадать с именем функции, просто записали строку в него.</dd>
<dd>Должно совпадать с именем функции.</dd>
<dt>`message` -- сообщение об ошибке.</dt>
<dd>Несмотря на то, что `PropertyError` наследует от `Error` (последняя строка), конструктор у неё немного другой. Он принимает не сообщение об ошибке, а название свойства `property`, ну а сообщение генерируется из него.
В результате в ошибке есть как стандартное свойство `message`, так и более точное `property`.
В результате в объекте ошибки есть как стандартное свойство `message`, так и более точное `property`.
Это полезная практика -- добавлять в объект ошибки свойства, более подробно описывающие ситуацию, которых нет в базовых объектах `Error`.</dd>
Это частая практика -- добавлять в объект ошибки свойства, которых нет в базовых объектах `Error`, более подробно описывающие ситуацию для данного класса ошибок.</dd>
<dt>`stack` -- стек вызовов, которые в итоге привели к ошибке.</dt>
<dd>У встроенных объектов `Error` это свойство есть автоматически, вот к примеру:
```js
@ -53,30 +53,28 @@ function f() {
alert( new Error().stack );
}
f();
f(); // выведет список вложенных вызовов, с номерами строк, где они были сделаны
```
Если же объект делаем мы, то "по умолчанию" такого свойства у него не будет. Нам нужно как-то самим узнавать последовательность вложенных вызовов на текущий момент. Однако удобного способа сделать это в JavaScript нет, поэтому мы поступаем хитро и копируем его из нового объекта `new Error`, который генерируем тут же.
Если же объект ошибки делаем мы, то "по умолчанию" у него такого свойства у него не будет. Нам нужно как-то самим узнавать последовательность вложенных вызовов на текущий момент. Однако удобного способа сделать это в JavaScript нет, поэтому мы поступаем хитро и копируем его из нового объекта `new Error`, который генерируем тут же.
В V8 (Chrome, Opera, Node.JS) есть нестандартное расширение [Error.captureStackTrace](https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi), которое позволяет стек получать.
Строка из кода выше:
Это делает строка из кода выше:
```js
Error.captureStackTrace(this, PropertyError);
```
Вызов записывает в объект `this` (текущий объект ошибки) стек вызовов, а второй аргумент -- это текущий конструктор, он не обязателен, но если есть, то говорит, что при генерации стека нужно на этой функции остановиться. В результате в стеке не будет информации о том, что делалось внутри конструктора `PropertyError`.
Такой вызов записывает в объект `this` (текущий объект ошибки) стек вызовов, ну а второй аргумент -- вообще не обязателен, но если есть, то говорит, что при генерации стека нужно на этой функции остановиться. В результате в стеке будет информация о цепочке вложенных вызовов вплоть до вызова `PropertyError`.
То есть, будет последовательность вызовов до генерации ошибки, но не включая код самого конструктора ошибки, который, как правило, не интересен. Такое поведение максимально соответствует встроенным ошибкам JavaScript.
</dd>
</dl>
[smart header="Конструктор родителя здесь не нужен"]
В коде выше не вызывается конструктор родителя. Обычно, когда мы наследуем, то мы вызываем его.
Обычно, когда мы наследуем, то вызываем конструктор родителя. В данном случае вызов выглядел бы как `Error.call(this, message)`.
В данном случае вызов выглядел бы как `Error.call(this, message)`.
Однако, встроенный конструктор `Error` на редкость прост, он ничего полезного не делает, даже свойство `this.message` (не говоря уже об `name` и `stack`) не назначает. Поэтому и вызывать его здесь нет необходимости.
Однако, встроенный конструктор `Error` ничего полезного не делает, даже свойство `this.message` (не говоря уже об `name` и `stack`) не назначает. Поэтому и вызывать его здесь нет необходимости.
[/smart]
@ -93,7 +91,7 @@ function PropertyError(property) {
this.name = "PropertyError";
this.property = property;
this.message = "Отсутствует свойство " + property;
this.message = "Ошибка в свойстве " + property;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, PropertyError);
@ -137,49 +135,50 @@ try {
alert( "Здравствуйте, Аноним!" );
*/!*
} else {
alert( err.message ); // Отсутствует свойство ...
alert( err.message ); // Ошибка в свойстве ...
}
} else if (err instanceof SyntaxError) {
alert( "Ошибка в данных: " + err.message );
alert( "Ошибка в синтаксисе данных: " + err.message );
} else {
throw err; // неизвестная ошибка, не знаю что с ней делать
}
}
```
Обратим внимание на проверку типа ошибки в `try..catch`.
Всё работает -- и наша ошибка `PropertyError` и встроенная `SyntaxError` корректно генерируются, перехватываются, обрабатываются.
Оператор `instanceof` поддерживает иерархию. Это значит, что если мы в дальнейшем решим как-то ещё уточнить тип ошибки `PropertyError`, то для объекта, наследующего от него, `e instanceof PropertyError` по-прежнему будет работать.
Обратим внимание на проверку типа ошибки в `try..catch`. Оператор `instanceof` проверяет класс с учётом наследования. Это значит, что если мы в дальнейшем решим создать новый тип ошибки, наследующий от `PropertyError`, то проверка `err instanceof PropertyError` для класса-наследника тоже будет работать. Код получился расширяемым, это очень важно.
## Дальнейшее наследование
Чтобы создать иерархию, нужно наследовать от `PropertyError`.
`PropertyError` -- это просто общего вида ошибка в свойстве. Создадим ошибку `PropertyRequiredError`, которая означает, что свойства нет.
Типичный вид конструктора-наследника -- такой:
Эт подвид `PropertyError`, так что унаследуем он неё. Общий вид конструктора-наследника -- стандартный:
```js
function PropertyRequiredError(property) {
// вызываем конструктор родителя и передаём текущие аргументы
PropertyError.apply(this, arguments);
...
}
```
Можем ли мы просто вызвать конструктор родителя и ничего не делать в дополнение? Увы, нет.
Достаточно ли в наследнике просто вызвать конструктор родителя? Увы, нет.
Если так поступить, то свойство `this.name` будет некорректным, да и `Error.captureStackTrace` тоже получит неправильную функцию вторым параметром.
Можно ли как-то поправить конструктор родителя? Убрать из него все упоминания о конкретном классе `PropertyError` и сделать код универсальным?
Можно ли как-то поправить конструктор родителя, чтобы от него было проще наследовать?
Частично -- да. Как мы помним, существует свойство `constructor`, которое есть в `prototype` по умолчанию, и которое мы можем намеренно сохранить при наследовании:
Для этого нужно убрать из него упоминания о конкретном классе `PropertyError`, чтобы сделать код универсальным. Частично -- это возможно. Как мы помним, существует свойство `constructor`, которое есть в `prototype` по умолчанию, и которое мы можем намеренно сохранить при наследовании.
Исправим родителя `PropertyError` для более удобного наследования от него:
```js
function PropertyError(property) {
this.name = "PropertyError";
this.property = property;
this.message = "Отсутствует свойство " + property;
this.message = "Ошибка в свойстве " + property;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, *!*this.constructor*/!*); // (*)
@ -195,9 +194,9 @@ PropertyError.prototype.constructor = PropertyError;
*/!*
```
В строке `(*)` это свойство было использовано, чтобы получить конструктор уже не в виде жёсткой ссылки `PropertyError`, а тот, который использован для текущего объекта. В наследнике там будет `PropertyRequiredError`, как и задумано.
В строке `(*)` вместо ссылки на `PropertyError` используем `constructor` чтобы получить именно конструктор для текущего объекта. В наследнике там будет `PropertyRequiredError`, как и задумано.
Мы убрали одно упоминание, но с `this.name`, увы, сложности. Сейчас при наследовании оно будет всегда `"PropertyError"`. Все браузеры, кроме IE11-, поддерживают имя у Function Declaration, то есть имя функции можно было бы получить из `this.constructor.name`, но в IE11- это работать не будет.
Мы убрали одну жёсткую привязку к `PropertyError`, но со второй (`this.name`), увы, сложности. Оно должно содержать имя ошибки, то есть, имя её функции-конструктора. Его можно получить через `this.name = this.constructor.name`, но в IE11- это работать не будет.
Если подерживать IE11-, то тут уж придётся в наследнике его записывать вручную.
@ -218,13 +217,68 @@ var err = new PropertyRequiredError("age");
alert( err instanceof PropertyError ); // true
```
Здесь заодно и `message` было перезаписано на более точное. Если хочется избежать записи и перезаписи, то можно оформить его в виде геттера через `Object.defineProperty`.
Здесь заодно и `message` в наследнике было перезаписано на более точное. Если хочется избежать записи и перезаписи, то можно оформить его в виде геттера через `Object.defineProperty`.
## Итого
<ul>
<li>Чтобы наследовать встроенному классу ошибок `Error`, нужно самостоятельно позаботиться о `name`, `message` и `stack`.</li>
<li>Благодаря `instanceof` мы получили удобную поддержку иерархии ошибок, с возможностью в любой момент добавить новые классы, понятным кодом и предсказуемым поведением.</li>
<li>Чтобы наследовать от ошибок `Error`, нужно самостоятельно позаботиться о `name`, `message` и `stack`.</li>
<li>Благодаря тому, что `instanceof` поддерживает наследование, удобно организуются проверки на нужный тип. В иерархию ошибок можно в любой момент добавить новые классы, с понятным кодом и предсказуемым поведением.</li>
</ul>
Чтобы создавать наследники от `Error` было проще, можно создать класс `CustomError`, записать в него универсальный код, наподобие `PropertyError` и далее наследовать уже от него.
Чтобы создавать наследники от `Error` было проще, можно создать класс `CustomError`, записать в него универсальный код, наподобие `PropertyError` и далее наследовать уже от него:
```js
*!*
// общего вида "наша" ошибка
*/!*
function CustomError(message) {
this.name = "CustomError";
this.message = message;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error()).stack;
}
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
*!*
// наследник
*/!*
function PropertyError(property) {
CustomError.call(this, "Отсутствует свойство " + property)
this.name = "PropertyError";
this.property = property;
}
PropertyError.prototype = Object.create(CustomError.prototype);
PropertyError.prototype.constructor = PropertyError;
*!*
// и ещё уровень
*/!*
function PropertyRequiredError(property) {
PropertyError.call(this, property);
this.name = 'PropertyRequiredError';
this.message = 'Отсутствует свойство ' + property;
}
PropertyRequiredError.prototype = Object.create(PropertyError.prototype);
PropertyRequiredError.prototype.constructor = PropertyRequiredError;
*!*
// использование
*/!*
var err = new PropertyRequiredError("age");
// пройдёт проверку
alert( err instanceof PropertyRequiredError ); // true
alert( err instanceof PropertyError ); // true
alert( err isntanceof CustomError ); // true
alert( err isntanceof Error ); // true
```

View file

@ -0,0 +1,174 @@
# Примеси
В JavaScript невозможно унаследовать от двух и более объектов. Ссылка `__proto__` -- только одна.
Но потребность такая существует -- к примеру, мы написали код, релизующий методы работы с шаблонизатором или методы по обмену событиями, и хочется легко и непринуждённо добавлять эти возможности к любому классу.
Обычно это делают через примеси.
Примесь (англ. mixin) -- класс или объект, реализующий какое-либо чётко выделенное поведение. Используется для уточнения поведения других классов, не предназначен для самостоятельного использования.
<!--break-->
## Пример примеси
Самый простой вариант примеси -- это объект с полезными методами, которые мы просто копируем в нужный прототип.
Например:
```js
//+ run
*!*
// примесь
*/!*
var sayHiMixin = {
sayHi: function() {
alert("Привет " + this.name);
},
sayBye: function() {
alert("Пока " + this.name);
}
};
*!*
// использование:
*/!*
function User(name) {
this.name = name;
}
// передать методы примеси
for(var key in sayHiMixin) User.prototype[key] = sayHiMixin[key];
// User "умеет" sayHi
new User("Вася").sayHi(); // Привет Вася
```
Как видно из примера, методы примеси активно используют `this` и предназначены именно для запуска в контексте "объекта-носителя примеси".
Если какие-то из методов примеси не нужны -- их можно перезаписать своими после копирования.
## Примесь для событий
Теперь пример из реальной жизни.
Важный аспект, который может понадобиться объектам -- это умение работать с событиями.
То есть, чтобы объект мог специальным вызовом генерировать "уведомление о событии", а на эти уведомления другие объекты могли "подписываться", чтобы их получать.
Например, объект "Пользователь" при входе на сайт может генерировать событие `"login"`, а другие объекты, например "Календарь" может такие уведомления получать и подгружать информацию о пользователе.
Или объект "Меню" может при выборе пункта меню генерировать событие `"select"` с информацией о выбранном пункте меню, а другие объекты -- подписавшись на это событие, будут узнавать об этом.
События -- это средство "поделиться информацией" с неопределённым кругом заинтересованных лиц. А там уже кому надо -- тот среагирует.
Примесь `eventMixin`, реализующая события:
```js
var eventMixin = {
/**
* Подписка на событие
* Использование:
* menu.on('select', function(item) { ... }
*/
on: function(eventName, handler) {
if (!this._eventHandlers) this._eventHandlers = {};
if (!this._eventHandlers[eventName]) {
this._eventHandlers[eventName] = [];
}
this._eventHandlers[eventName].push(handler);
},
/**
* Прекращение подписки
* menu.off('select', handler)
*/
off: function(eventName, handler) {
var handlers = this._eventHandlers && this._eventHandlers[eventName];
if (!handlers) return;
for(var i=0; i<handlers.length; i++) {
if (handlers[i] == handler) {
handlers.splice(i--, 1);
}
}
},
/**
* Генерация события с передачей данных
* this.trigger('select', item);
*/
trigger: function(eventName /*, ... */) {
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
return; // обработчиков для события нет
}
// вызвать обработчики
var handlers = this._eventHandlers[eventName];
for (var i = 0; i < handlers.length; i++) {
handlers[i].apply(this, [].slice.call(arguments, 1));
}
}
};
```
Здесь есть три метода:
<ol>
<li>`.on(имя события, функция)` -- назначает функцию к выполнению при наступлении события с данным именем. Такие функции хранятся в защищённом свойстве объекта `_eventHandlers`.</li>
<li>`.off(имя события, функция)` -- удаляет функцию из списка предназначенных к выполнению.</li>
<li>`.trigger(имя события, аргументы)` -- генерирует событие, при этом вызываются все назначенные на него функции, и им передаются аргументы.</li>
</ol>
Использование:
```js
//+ run
// Класс Menu с примесью eventMixin
function Menu() {
// ...
}
for(var key in eventMixin) Menu.prototype[key] = eventMixin[key];
// Генерирует событие select при выборе значения
Menu.prototype.choose = function(value) {
*!*
this.trigger("select", value);
*/!*
}
// Создадим меню
var menu = new Menu();
// При наступлении события select вызвать эту функцию
*!*
menu.on("select", function(value) {
alert("Выбрано значение " + value);
});
*/!*
// Запускаем выбор (сработает событие)
menu.choose("123");
```
...То есть, смысл событий -- обычно в том, что объект, в процессе своей деятельности, внутри себя (`this.trigger`) генерирует уведомления, на которые внешний код через `menu.on(...)` может быть подписан. И узнавать из них ценную информцию о происходящем, например -- что выбран некий пункт меню.
Один раз написав методы `on/off/trigger` в примеси, мы затем можем использовать их во множестве прототипов.
## Итого
<ul>
<li>Примесь -- объект, содержащий методы и свойства для реализации конкретного функционала.
Возможны вариации этого приёма проектирования. Например, примесь может предусматривать конструктор, который должен запускаться в конструкторе объекта. Но как правило просто набора методов хватает.</li>
<li>Для добавления примеси в класс -- её просто "подмешивают" в прототип.</li>
<li>"Подмешать" можно сколько угодно примесей, но если имена методов в разных примесях совпадают, то возможны конфликты. Их уже разрешать -- разработчику. Например, можно заменить конфликтующий метод на свой, который будет решать несколько задач сразу. Конфликты при грамотно оформленных примесях возникают редко.</li></ul>

View file

@ -0,0 +1,21 @@
Двузначное шестнадцатиричное число -- это ``pattern`[0-9a-f]{2}` (с учётом флага ``pattern`/i`).
Нам нужно одно такое число, и за ним ещё 5 с двоеточиями перед ними: ``pattern`[0-9a-f]{2}(:[0-9a-f]{2}){5}`
И, наконец, совпадение должно начинаться в начале строки и заканчиваться -- в конце. То есть, строка целиком должна подходить под шаблон. Для этого обернём шаблон в ``pattern`^...$`.
Итого, в действии:
```js
//+ run
var re = /^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}$/i;
alert( re.test('01:32:54:67:89:AB') ); // true
alert( re.test('0132546789AB') ); // false (нет двоеточий)
alert( re.test('01:32:54:67:89') ); // false (5 чисел, а не 6)
alert( re.test('01:32:54:67:89:ZZ') ) // false (ZZ в конце)
```

View file

@ -0,0 +1,20 @@
# Проверьте MAC-адрес
MAC-адрес сетевого интерфейса состоит из шести двузначиных шестандцатиричных чисел, разделённых двоеточием.
Например: ``subject`'01:32:54:67:89:AB'`.
Напишите регулярное выражение, которое по строке проверяет, является ли она корректным MAC-адресом.
Использование:
```js
var re = ваш регэксп
alert( re.test('01:32:54:67:89:AB') ); // true
alert( re.test('0132546789AB') ); // false (нет двоеточий)
alert( re.test('01:32:54:67:89') ); // false (5 чисел, а не 6)
alert( re.test('01:32:54:67:89:ZZ') ) // false (ZZ в конце)
```

View file

@ -0,0 +1,4 @@
# Предпросмотр (неготово)
Требуется добавить главу про предпросмотр lookahead.

View file

@ -1,4 +1,4 @@
# Найдите время
# Найдите время в одном из форматов
Время может быть в формате `часы:минуты` или `часы-минуты`. И часы и минуты состоят из двух цифр, например `09:00`, `21-30`.

View file

@ -0,0 +1,18 @@
Начало шаблона очевидно: ``pattern`<style`.
А вот дальше... Мы не можем написать просто ``pattern`<style.*?>`, так как ``match`<styler>` удовлетворяет этому регэкспу.
Нужно уточнить его. После ``match`<style` должен быть либо пробел, после которого может быть что-то ещё, либо закрытие тега.
На языке регэкспов: ``pattern`<style(>|\s.*?>)`.
В действии:
```js
//+ run
var re = /<style(>|\s.*?>)/g;
alert( "<style> <styler> <style test>".match(re) ); // <style>, <style test>
```

View file

@ -0,0 +1,14 @@
# Найдите тег style
Напишите регулярное выражение, которое будет искать в тексте тег `<style>`. Подходят как обычный тег `<style>`, так и вариант с атрибутами `<style type="...">`.
Но регулярное выражение не должно находить `<styler>`!
Использование:
```js
var re = ваш регэксп
alert( "<style> <styler> <style test>".match(re) ); // <style>, <style test>
```

View file

@ -1,3 +1,3 @@
# Регулярные выражения [незавершён]
# Регулярные выражения
Регулярные выражения -- мощный способ поиска и замены для строк.

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more