renovations

This commit is contained in:
Ilya Kantor 2015-03-06 17:10:55 +03:00
parent 2022aafc13
commit dceccedb58
60 changed files with 1730 additions and 272 deletions

View file

@ -8,7 +8,7 @@
[cut]
## str.search(regexp)
## str.search(reg)
Этот метод мы уже видели.
@ -25,11 +25,11 @@ alert( str.search( *!*/лю/i*/!* ) ); // 0
Нельзя заставить `search` искать дальше первого совпадения, такой синтаксис попросту не предусмотрен. Но есть другие методы, которые это умеют.
## str.match(regexp) без флага g
## str.match(reg) без флага g
Метод `str.match` работает по-разному, в зависимости от наличия или отсутствия флага `g`, поэтому сначала мы разберём вариант, когда его нет.
В этом случае `str.match(regexp)` находит только одно, первое совпадение.
В этом случае `str.match(reg)` находит только одно, первое совпадение.
Результат вызова -- это массив, состоящий из этого совпадения, с дополнительными свойствами `index` -- позиция, на которой оно обнаружено и `input` -- строка, в которой был поиск.
@ -68,7 +68,7 @@ alert( result.input ); // javascript - это такой язык
Позже мы ещё вернёмся к скобочным выражениям, они особенно удобны для поиска с заменой.
## str.match(regexp) с флагом g
## str.match(reg) с флагом g
При наличии флага `g`, вызов `match` возвращает обычный массив из всех совпадений.
@ -116,7 +116,7 @@ alert( str.match( /лю/gi ).length ) // ошибка! нет свойства l
```
[/warn]
## str.split(regexp|substr, limit)
## str.split(reg|substr, limit)
Разбивает строку в массив по разделителю -- регулярному выражению `regexp` или подстроке `substr`.
@ -136,7 +136,7 @@ alert( '12-34-56'.split('-') ) // [12, 34, 56]
alert( '12-34-56'.split(/-/) ) // [12, 34, 56]
```
## str.replace(regexp, newStr|function)
## str.replace(reg, str|func)
Швейцарский нож для работы со строками, поиска и замены любого уровня сложности.
@ -158,6 +158,7 @@ alert( '12-34-56'.replace("-", ":") ) // 12:34-56
alert( '12-34-56'.replace( *!*/-/g*/!*, ":" ) ) // 12:34:56
```
В строке для замены можно использовать специальные символы:
<table>
@ -271,7 +272,7 @@ alert( str.replace( /(Василий) (Пупкин)/ , replacer) ) // Пупк
Метод `test` проверяет, есть ли хоть одно совпадение в строке `str`. Возвращает `true/false`.
Работает, по сути, так же, как и проверка `str.search(regexp) != -1`, например:
Работает, по сути, так же, как и проверка `str.search(reg) != -1`, например:
```js
//+ run
@ -306,7 +307,7 @@ alert( str.search(*!*/javascript/i*/!*) != -1 ) // false
Он ведёт себя по-разному, в зависимости от того, есть ли у регэкспа флаг `g`.
<ul>
<li>Если флага `g` нет, то `regexp.exec(str)` ищет и возвращает первое совпадение, является полным аналогом вызова `str.match(regexp)`.</li>
<li>Если флага `g` нет, то `regexp.exec(str)` ищет и возвращает первое совпадение, является полным аналогом вызова `str.match(reg)`.</li>
<li>Если флаг `g` есть, то вызов `regexp.exec` возвращает первое совпадение и *запоминает* его позицию в свойстве `regexp.lastIndex`. Последующий поиск он начнёт уже с этой позиции. Если совпадений не найдено, то сбрасывает `regexp.lastIndex` в ноль.</li>
</ul>
@ -350,36 +351,38 @@ alert( regexp.exec(str).index ); // 49, поиск начат с 40й позиц
Методы становятся гораздо понятнее, если разбить их использование по задачам, которые нужны в реальной жизни.
<dl>
<dt>Для поиска только одного совпадения:</dt>
<dd>
<ul>
<li>Для поиска только одного совпадения:
<dl>
<dt>Найти позицию первого совпадения</dt>
<dd>`str.search(regexp)`</dd>
<dt>Найти само совпадение</dt>
<dd>`str.match(regexp)`</dd>
<dt>Проверить, есть ли хоть одно совпадение</dt>
<dd>`regexp.test(str)`, также можно использовать `str.search(regexp) != -1`</dd>
<dt>Найти совпадение с нужной позиции</dt>
<dd>`regexp.exec(str)`, начальную позицию поиска задать в `regexp.lastIndex`</dd>
</dl>
</li>
<li>Для поиска всех совпадений:
<dl>
<dt>Найти массив совпадений</dt>
<dd>`str.match(regexp)`, с флагом `g`</dd>
<dt>Получить все совпадения, с подробной информацией о каждом</dt>
<dd>`regexp.exec(str)` с флагом `g`, в цикле</dd>
</dl>
</li>
<li>Дополнительно:
<dl>
<dt>Для поиска-и-замены</dt>
<dd>`str.replace(regexp, str|func)`</dd>
<dt>Для разбивки строки на части</dt>
<dd>`str.split(regexp)`</dd>
</dl>
</li>
<li>Найти позицию первого совпадения -- `str.search(reg)`.</li>
<li>Найти само совпадение -- `str.match(reg)`.</li>
<li>Проверить, есть ли хоть одно совпадение -- `regexp.test(str)` или `str.search(reg) != -1`.</li>
<li>Найти совпадение с нужной позиции -- `regexp.exec(str)`, начальную позицию поиска задать в `regexp.lastIndex`.</li>
</ul>
</dd>
<dt>Для поиска всех совпадений:</dt>
<dd>
<ul>
<li>Найти массив совпадений -- `str.match(reg)`, с флагом `g`.</li>
<li>Получить все совпадения, с подробной информацией о каждом -- `regexp.exec(str)` с флагом `g`, в цикле.</li>
</ul>
</dd>
</dt>
<dt>Для поиска-и-замены:</dt>
<dd>
<ul>
<li>Замена на другую строку или функцией -- `str.replace(reg, str|func)`</li>
</ul>
</dd>
<dt>Для разбивки строки на части:</dt>
<dd>
<ul>
<li>`str.split(str|reg)`</li>
</ul>
</dd>
</dl>
Теперь, зная общие методы, мы можем перейти к более подробному изучению синтаксиса регулярных выражений.
Зная эти методы, мы уже можем использовать регулярные выражения.
Конечно, для этого желательно хорошо понимать их синтаксис и возможности, так что переходим к ним дальше.

View file

@ -1,88 +1,95 @@
# Символьные классы [todo]
# Классы и спецсимволы
Рассмотрим задачу -- есть телефонный номер `"+7(903)-123-45-67"`, и нам нужно найти в этой строке цифры, а остальные символы нас не интересуют.
Рассмотрим практическую задачу -- есть телефонный номер `"+7(903)-123-45-67"`, и нам нужно найти в этой строке цифры. А остальные символы нас не интересуют.
Для поиска символов определённого вида в регулярных выражениях предусмотрены "классы символов".
**Для поиска символов определённого вида, в регулярных выражениях предусмотрены "классы символов".**
[cut]
Класс символов -- это, в первую очередь, специальное обозначение.
Например, в данном случае нам нужен класс "произвольная цифра", он обозначается `\d`.
Класс символов -- это специальное обозначение, под которое подходит любой символ данного класса.
Это обозначение вставляется в паттерн наравне с остальными символами. При поиске под него подходит любая цифра.
Например, класс "любая цифра" обозначается `\d`. Это обозначение вставляется в паттерн наравне с остальными символами, и при поиске под него подходит любая цифра.
Пример ниже ищет все цифры в строке:
Регулярное выражение <code class="pattern">/\d/</code> ищет ровно одну цифру (первую):
```js
//+ run
var str = "+7(903)-123-45-67";
var reg = /\d/g
var reg = /\d/;
alert( str.match(reg) ); // 7,9,0,3,1,2,3,4,5,6,7
alert( str.match(reg) ); // 7
```
Есть и другие классы. Самые полезные:
...Ну а для поиска всех цифр достаточно добавить к нему флаг `g`:
```js
//+ run
var str = "+7(903)-123-45-67";
var reg = /\d/g;
alert( str.match(reg) ); // массив цифр: 7,9,0,3,1,2,3,4,5,6,7
```
## Важнейшие классы
Это был класс для цифр.
Конечно же, есть и другие. Самые полезные классы:
<dl>
<dt>`\d` (от английского "digit" - "цифра")</dt>
<dd>Цифра, символ от `0` до `9`.</dd>
<dt>`\s` (от английского "space" - "пробел")</dt>
<dd>Пробельный символ, включая табы, переводы строки и т.п.</dd>
<dt>`\w` (от английского "word" -- "слово") </dt>
<dd>Символ латинского алфавита или цифра или подчёркивание `'_'`</dd>
<dd>Символ латинского алфавита или цифра или подчёркивание `'_'`. Не-английские буквы не являются `\w`.</dd>
</dl>
**Регулярное выражение обычно содержит одновременно и обычные символы и классы**:
Регулярное выражение как правило содержит одновременно и обычные символы и классы.
Например, найдём строку `CSS` с любой цифровой версией:
Например, <code class="pattern">CSS\d</code> найдёт строку <code class="match">CSS</code>, с любой цифрой после неё.
Пример ниже найдёт строку `CSS` с любой цифровой версией:
```js
//+ run
var str = "Стандарт CSS4 - наше будущее";
var str = "Стандарт CSS4 - это здорово";
var reg = /CSS\d/
alert( str.match(reg) );
alert( str.match(reg) ); // CSS4
```
Несколько классов в одном регэкспе:
Можно указать и несколько классов в одном регэкспе:
```js
//+ run
showMatch( "Я люблю HTML5!", /\s\w\w\w\w\d/ ); // 'HTML5'
alert( "Я люблю HTML5!".match(/\s\w\w\w\w\d/) ); // 'HTML5'
```
Совпадение (каждому классу в регэкспе соответствует один символ результата):
<img src="love_html5.png">
**Также существуют обратные символьные классы:**
## Обратные классы
Для каждого символьного класса существует "обратный ему", представленный такой же, но заглавной буквой.
"Обратный" -- означает, что ему соответствуют все остальные символы, например:
<dl>
<dt>`\D`</dt>
<dd>Не-цифра, любой символ кроме `\d`</dd>
<dd>Не-цифра, то есть любой символ кроме `\d`, например буква.</dd>
<dt>`\S`</dt>
<dd>Не-пробел, любой символ кроме `\s`.</dd>
<dd>Не-пробел, то есть любой символ кроме `\s`, например буква.</dd>
<dt>`\W`</dt>
<dd>Символ, не принадлежащий латиннице, а также не буква и не подчёркивание, алфавиту, т.е. любой кроме `\w`</dd>
<dd>Любой символ, кроме `\w`, то есть не латинница, не подчёркивание, не цифра. В частности, русские буквы принадлежат этому классу.</dd>
</dl>
Например, мы хотим получить из телефона <code class="subject">+7(903)-123-45-67</code> только цифры.
В начале этой главы мы видели, как получить из телефона <code class="subject">+7(903)-123-45-67</code> все цифры.
Есть два способа сделать это.
<ol>
<li>Первый -- найти все цифры и объединить их:
Например:
```js
//+ run
var str = "+7(903)-123-45-67";
var digits = str.match( /\d/g ).join("");
alert(digits); // 79031234567
```
</li>
<li>Второй -- найти все НЕцифры и удалить их из строки:
Первый способ -- найти все цифры через `match(/\d/g)`, но есть и альтернативный -- найти все НЕцифры и удалить их из строки:
```js
//+ run
@ -91,53 +98,59 @@ var str = "+7(903)-123-45-67";
alert( str.replace(/\D/g, "") ); // 79031234567
```
Второй способ короче, не правда ли?
</li>
</ol>
## Спецсимволы
**Регулярное выражение может также содержать стандартные спецсимволы строк, такие как `\n, \t` и другие.**
Регулярное выражение может также содержать стандартные спецсимволы строк, такие как перевод строки `\n`, табуляцию `\t` и другие.
Они являются обычными символами. Отличить их от классов очень просто -- для классов зарезервированы другие буквы.
Отличить их от классов очень просто -- для классов зарезервированы другие буквы. Так что никакого конфликта здесь нет.
## Пробелы
[warn header="Пробелы важны!"]
Обычно мы не обращаем внимание на пробелы. Для нашего взгляда строки <code class="subject">1-5</code> и <code class="subject">1 - 5</code> почти идентичны.
Но в регулярных выражениях **пробел - такой же символ, как и другие**.
Но в регулярных выражениях пробел - такой же символ, как и другие.
Поиск ниже не сработает, т.к. не учитывает пробелы вокруг дефиса:
Поиск ниже не сработает, так как не учитывает пробелы вокруг дефиса:
```js
//+ run
alert( "1 - 5".match (/\d-\d/) ); // null, нет совпадений!
```
Поправим это, добавив в паттерн пробелы:
Поправим это, добавив в регэксп пробелы:
```js
//+ run
alert( "1 - 5".match (/\d - \d/) ); // работает, пробелы вокруг дефиса
```
В регулярные выражения также не надо вставлять лишние пробелы. Все они имеют значение:
В регулярные выражения также не надо вставлять лишние пробелы. Все символы имеют значение:
```js
//+ run
alert( "1-5".match( /\d - \d/ ) ); // null, так как в строке 1-5 нет пробелов
```
[/warn]
## Класс точка
Особым классом символов является точка `"."`.
**В регулярном выражении, точка <code class="pattern">"."</code> обозначает *любой символ*, кроме перевода строки**:
В регулярном выражении, точка <code class="pattern">"."</code> обозначает *любой символ*, кроме перевода строки:
```js
//+ run
alert( "Z".match(/./) ); // найдено Z
```
Посередине регулярного выражения:
```js
//+ run
var re = /CS.4/;
alert( "Стандарт CSS4".match(re) ); // найдено "CSS4"
alert( "Сталь CS-4".match(re) ); // найдено "CS-4"
alert( "CS 4".match(re) ); // найдено "CS 4", пробел тоже символ
alert( "CSS4".match(re) ); // найдено "CSS4"
alert( "CS-4".match(re) ); // найдено "CS-4"
alert( "CS 4".match(re) ); // найдено "CS 4" (пробел тоже символ)
```
Обратим внимание -- точка означает именно "произвольный символ".
@ -146,7 +159,71 @@ alert( "CS 4".match(re) ); // найдено "CS 4", пробел тоже си
```js
//+ run
alert( "CS4".match (/CS.4/) ); // нет совпадений, так как для точки нет символа
```
## Экранирование специальных символов
В регулярных выражениях есть и другие символы, имеющие особый смысл.
Они используются, чтобы расширить возможности поиска.
Вот их полный список: <code class="pattern">[ \ ^ $ . | ? * + ( )</code>.
Не пытайтесь запомнить его -- когда мы разберёмся с каждым из них по отдельности, он запомнится сам собой.
**Чтобы использовать специальный символ в качестве обычного, он должен быть *экранирован*.**
Или, другими словами, перед символом должен быть обратный слэш `'\'`.
Например, нам нужно найти точку <code class="pattern">'.'</code>. В регулярном выражении она означает "любой символ, кроме новой строки", поэтому чтобы найти именно сам символ "точка" -- её нужно экранировать: <code class="pattern">\.</code>.
```js
//+ run
alert( "Глава 5.1".match( /\d\.\d/ ) ); // 5.1
```
Круглые скобки также являются специальными символами, так что для поиска именно скобки нужно использовать `\(`. Пример ниже ищет строку `"g()"`:
```js
//+ run
alert( "function g()".match( /g\(\)/ ) ); // "g()"
```
Сам символ слэш `'/'`, хотя и не является специальными символом в регулярных выражениях, но открывает-закрывает регэксп в синтаксисе <code class="pattern">/...pattern.../</code>, поэтому его тоже нужно экранировать.
Так выглядит поиск слэша `'/'`:
```js
//+ run
alert( "/".match( /\// ) ); // '/'
```
Ну и, наконец, если нам нужно найти сам обратный слэш `\`, то его нужно просто задублировать.
Так выглядит поиск обратного слэша `"\"`:
```js
//+ run
alert( "1\2".match( /\\/ ) ); // '\'
```
## Итого
Мы рассмотрели классы для поиска типов символов:
<ul>
<li>`\d` -- цифры.</li>
<li>`\D` -- не-цифры.</li>
<li>`\s` -- пробельные символы, переводы строки.</li>
<li>`\S` -- всё, кроме `\s`.</li>
<li>`\w` -- латинница, цифры, подчёркивание `'_'`.</li>
<li>`'.'` -- точка обозначает любой символ, кроме перевода строки.</li>
</ul>
Кроме того, в регэкспах допустимы и обычные спец-символы строк, например `\n`.
Если хочется поискать именно точку или какой-то другой "особый" символ, то его экранируют: <code class="pattern">\.</code>

View file

@ -1,46 +0,0 @@
# Экранирование специальных символов
В регулярных выражениях есть и другие символы, имеющие особый смысл.
Они используются, чтобы расширить возможности поиска.
Вот их полный список: <code class="pattern">[ \ ^ $ . | ? * + ( )</code>.
Не пытайтесь запомнить его -- когда мы разберёмся с каждым из них по отдельности, он запомнится сам собой.
**Чтобы использовать специальный символ в качестве обычного, он должен быть *экранирован*.**
Или, другими словами, перед символом должен быть обратный слэш `'\'`.
Например, нам нужно найти точку <code class="pattern">'.'</code>. В регулярном выражении она означает "любой символ, кроме новой строки", поэтому чтобы найти именно сам символ "точка" -- её нужно экранировать: <code class="pattern">\.</code>.
```js
//+ run
alert( "Глава 5.1".match( /\d\.\d/ ) ); // 5.1
```
Круглые скобки также являются специальными символами, так что для поиска именно скобки нужно использовать `\(`. Пример ниже ищет строку `"g()"`:
```js
//+ run
alert( "function g()".match( /g\(\)/ ) ); // "g()"
```
**Слэш `'/'`, хотя и не является специальными символом, но открывает-закрывает регэксп в синтаксисе <code class="pattern">/...pattern.../</code>. Поэтому его тоже нужно экранировать: <code><code>'\/'</code></code>**.
Так выглядит поиск слэша `'/'`:
```js
//+ run
alert( "/".match( /\// ) ); // '/'
```
Ну и, наконец, если нам нужно найти сам обратный слэш `\`, то его нужно просто задублировать.
Так выглядит поиск обратного слэша `"\"`:
```js
//+ run
alert( "1\2".match( /\\/ ) ); // '\'
```

View file

@ -1,12 +1,14 @@
# Наборы и диапазоны [...]
Если в регулярном выражении нескольки символов или символьных классов заключены в квадратные скобки `[…]`, то это означает "искать любой символ из указанных в `[…]`".
Если в регулярном выражении несколько символов или символьных классов заключены в квадратные скобки `[…]`, то это означает "искать любой символ из указанных в `[…]`".
[cut]
## Набор
Например, <code class="pattern">[еао]</code> означает любой символ из этих трёх: `'а'`, `'е'`, или `'о'`.
[cut]
Можно использовать квадратные скобки вместе с обычными символами.
Например:
Такое обозначение называют *набором*. Наборы используются в регулярном выражении наравне с обычными символами:
```js
//+ run
@ -14,7 +16,7 @@
alert( "Гоп-стоп".match( /[гт]оп/gi ) ); // "Гоп", "топ"
```
Несмотря на то, что в квадратных скобках несколько символов, в совпадении должен присутствовать *ровно один* из них.
Обратим внимание: несмотря на то, что в наборе указано несколько символов, в совпадении должен присутствовать *ровно один* из них.
Поэтому в примере ниже нет результатов:
@ -24,13 +26,22 @@ alert( "Гоп-стоп".match( /[гт]оп/gi ) ); // "Гоп", "топ"
alert( "Вуаля".match( /В[уа]ля/ ) ); // совпадений нет
```
Совпадение было бы, если бы после `"Ву"` шло сразу `"ля"`, например <code class="subject">Вуля</code> или если бы `"Ва"` сопровождалось `"ля"`, то есть <code class="subject">Валя</code>.
Поиск подразумевает:
<ul>
<li><code class="pattern">В</code>,</li>
<li>затем *одну* из букв набора <code class="pattern">[уа]</code>,</li>
<li>а затем <code class="pattern">ля</code></li>
</ul>
**Квадратные скобки могут также содержать *диапазоны символов*.**
Таким образом, совпадение было бы для строки <code class="match">Вуля</code> или <code class="match">Валя</code>.
## Диапазоны
Квадратные скобки могут также содержать *диапазоны символов*.
Например, <code class="pattern">[a-z]</code> -- произвольный символ от `a` до `z`, <code class="pattern">[0-5]</code> -- цифра от `0` до `5`.
В примере ниже мы будем искать `"x"`, после которого идёт два раза `[0-9A-F]` -- цифра или буква от A до F:
В примере ниже мы будем искать `"x"`, после которого идёт два раза любая цифра или буква от A до F:
```js
//+ run
@ -38,7 +49,7 @@ alert( "Вуаля".match( /В[уа]ля/ ) ); // совпадений нет
alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) );
```
Обратим внимание, в слове <code class="subject">Exception</code> есть сочетание <code class="subject">xce</code>, но оно не подошло, потому что буквы в нём маленькие, а в диапазоне -- большие.
Обратим внимание, в слове <code class="subject">Exception</code> есть сочетание <code class="subject">xce</code>, но оно не подошло, потому что буквы в нём маленькие, а в диапазоне <code class="pattern">[0-9A-F]</code> -- большие.
Если хочется искать и его тоже, можно добавить в скобки диапазон `a-f`: <code class="pattern">[0-9A-Fa-f]</code>. Или же просто указать у всего регулярного выражения флаг `i`.
@ -50,9 +61,9 @@ alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) );
<li>**\s** -- то же самое, что <code class="pattern">[\t\n\v\f\r ]</code> плюс несколько юникодных пробельных символов.</li>
</ul>
**В квадратных скобках можно использовать и диапазоны и символьные классы -- вместе.**
В квадратных скобках можно использовать и диапазоны и символьные классы -- вместе.
Например, нам нужно найти слова в тексте. Если оно на английском -- это достаточно просто:
Например, нам нужно найти все слова в тексте. Если они на английском -- это достаточно просто:
```js
//+ run
@ -72,7 +83,9 @@ alert( str.match( /\w+/g ) ); // null*!*
Ничего не найдено! Это можно понять, ведь <code class="pattern">\w</code> -- это именно английская букво-цифра, как можно видеть из аналога <code class="pattern">[a-zA-Z0-9_]</code>.
Чтобы находило слово на русском -- нужно использовать диапазон, например <code class="pattern">/[а-я]/</code>. А чтобы на обоих языках -- и то и другое вместе:
Чтобы находило слово на русском -- нужно использовать диапазон, например <code class="pattern">/[а-я]/</code>.
А чтобы на обоих языках -- и то и другое вместе:
```js
//+ run
@ -81,7 +94,9 @@ var str = "Солнце (the sun) встаёт!";
alert( str.match( /[\wа-я]+/gi ) ); // Солнце, the, sun, вста, т*!*
```
...Присмотритесь внимательно к предыдущему примеру! Вы видите странность? Оно не находит букву <code class="match">ё</code>, более того -- считает её разрывом в слове. Причина -- в кодировке юникод, она подробно раскрыта в главе [](/string). Буква `ё` лежит в стороне от основной кириллицы и её следует добавить в диапазон дополнительно, вот так:
...Присмотритесь внимательно к предыдущему примеру! Вы видите странность? Оно не находит букву <code class="match">ё</code>, более того -- считает её разрывом в слове. Причина -- в кодировке юникод, она подробно раскрыта в главе [](/string).
Буква `ё` лежит в стороне от основной кириллицы и её следует добавить в диапазон дополнительно, вот так:
```js
//+ run
@ -92,6 +107,8 @@ alert( str.match( /[\wа-яё]+/gi ) ); // Солнце, the, sun, встаёт*
Теперь всё в порядке.
## Диапазоны "кроме"
**Кроме обычных, существуют также *исключающие* диапазоны: <code class="pattern">[^…]</code>.**
Квадратные скобки, начинающиеся со знака каретки: <code class="pattern">[^…]</code> находят любой символ, *кроме указанных*.
@ -99,9 +116,9 @@ alert( str.match( /[\wа-яё]+/gi ) ); // Солнце, the, sun, встаёт*
Например:
<ul>
<li><code class="pattern">[^аеуо]</code> -- любой символ, кроме `'a'`, `'e'`, `'y'`, `'o'`</li>
<li><code class="pattern">[^0-9]</code> -- любая не-цифра, то же что `\D`</li>
<li><code class="pattern">[^\s]</code> -- любой не-пробельный символ, как и `\S`</li>
<li><code class="pattern">[^аеуо]</code> -- любой символ, кроме `'a'`, `'e'`, `'y'`, `'o'`.</li>
<li><code class="pattern">[^0-9]</code> -- любой символ, кроме цифры, то же что `\D`.</li>
<li><code class="pattern">[^\s]</code> -- любой не-пробельный символ, то же что `\S`.</li>
</ul>
Пример ниже ищет любые символы, кроме букв, цифр и пробелов:
@ -111,28 +128,31 @@ alert( str.match( /[\wа-яё]+/gi ) ); // Солнце, the, sun, встаёт*
alert( "alice15@gmail.com".match( /[^\d\sA-Z]/gi ) ); // "@", "."
```
**В квадратных скобках большинство специальных символов можно использовать без экранирования.**
## Не нужно экранирование
Обычно, если мы хотим искать именно точку, а не любой символ, или именно `"\d"`, а не произвольную цифру, то мы используем экранирование: указываем `\.` или `\\d`.
Обычно, если мы хотим искать именно точку, а не любой символ, или именно символ `\`, то мы используем экранирование: указываем `\.` или `\\`.
Но квадратные скобки подразумевают поиск одного символа из нескольких или из диапазона. Использование некоторых специальных символов внутри них не имело бы смысла, и они воспринимаются как обычные символы.
В квадратных скобках большинство специальных символов можно использовать без экранирования, если конечно ни не имеют какой-то особый смысл именно внутри квадратных скобок.
Это касается символов:
То есть, "как есть", без экранирования можно использовать символы:
<ul>
<li>точка <code class="pattern">'.'</code></li>
<li>плюс <code class="pattern">'+'</code></li>
<li>круглые скобки <code class="pattern">'( )'</code></li>
<li>дефис <code class="pattern">'-'</code>, если он находится в начале или конце квадратных скобок, то есть не выделяет диапазон.</li>
<li>символ каретки <code class="pattern">'^'</code>, если не находится в начале квадратных скобок, то есть кроме <code class="pattern">[\^..]</code>.</li>
<li>а также открывающая квадратная скобка <code class="pattern">'['</code></li>
<li>Точка <code class="pattern">'.'</code>.</li>
<li>Плюс <code class="pattern">'+'</code>.</li>
<li>Круглые скобки <code class="pattern">'( )'</code>.</li>
<li>Дефис <code class="pattern">'-'</code>, если он находится в начале или конце квадратных скобок, то есть не выделяет диапазон.</li>
<li>Символ каретки <code class="pattern">'^'</code>, если не находится в начале квадратных скобок.</li>
<li>А также открывающая квадратная скобка <code class="pattern">'['</code>.</li>
</ul>
То есть, точка `"."` в квадратных скобках означает не "любой символ", а обычную точку.
Например, регэксп <code class="pattern">[-().^+]</code> ищет один из символов `-().^`. В данном контексте эти символы не являются специальными.
Регэксп <code class="pattern">[.,]</code> ищет один из символов "точка" или "запятая".
В примере ниже регэксп <code class="pattern">[-().^+]</code> ищет один из символов `-().^`. Они не экранированы:
```js
//+ run
// Без экранирования
var re = /[-().^+]/g;
alert( "1 + 2 - 3".match(re) ); // найдёт +, -
@ -142,6 +162,7 @@ alert( "1 + 2 - 3".match(re) ); // найдёт +, -
```js
//+ run
// Всё заэкранировали
var re = /[\-\(\)\.\^\+]/g;
alert( "1 + 2 - 3".match(re) ); // тоже работает: +, -

View file

@ -1,47 +0,0 @@
# Цифровые квантификаторы {n}
Рассмотрим задачу -- взять телефон вида `+7(903)-123-45-67` и найти все числа в нём. То есть, нас интересует результат вида `7, 903, 123, 45, 67`.
Нечто похожее мы уже делали ранее -- мы искали цифры. Для этого было достаточно класса `\d`. Но здесь нужно искать *числа* -- последовательности из 1 или более цифр.
**Количество повторений символа можно указать с помощью числа в фигурных скобках: `{n}`.**
<dl>
<dt>Точное количество: `{5}`</dt>
<dd>Паттерн <code class="pattern">\d{5}</code> обозначает 5 цифр, как и <code class="pattern>\d\d\d\d\d</code>.
Следующий пример находит пятизначное число.
```js
//+ run
alert( "Мне 12345 лет".match (/\d{5}/) ); // "12345"
```
</dd>
<dt>Количество от-до: `{3,5}`</dt>
<dd>Для того, чтобы найти, например, числа размером от трёх до пяти знаков, нужно указать границы в фигурных скобках: `\d{3,5}`
```js
//+ run
alert( "Мне не 12, а 1234 года".match( /\d{3,5}/ ) ); // "1234"
```
Последнее значение можно и не указывать. Тогда выражение `\d{3,}` найдет числа, длиной от трех знаков:
```js
//+ run
alert( "Мне не 12, а 345678 лет".match( /\d{3,5}/ ) ); // "345678"
```
</dd>
</dl>
В случае с телефоном нам нужны числа - одна или более цифр подряд. Этой задаче соответствует регулярное выражение <code class="pattern">\d{1,}</code>:
```js
//+ run
var str = "+7(903)-123-45-67";
alert( str.match( /\d{1,}/g ) ); // 7,903,123,45,67
```

View file

@ -1,8 +1,60 @@
# Квантификаторы +, * и ?
# Квантификаторы +, *, ? и {n}
Рассмотрим ту же задачу, что и ранее -- взять телефон вида `+7(903)-123-45-67` и найти все числа в нём. Но теперь нас интересуют не цифры по отдельности, а именно числа, то есть результат вида `7, 903, 123, 45, 67`.
Для поиска цифр по отдельности нам было достаточно класса `\d`. Но здесь нужно искать *числа* -- последовательности из 1 или более цифр.
## Количество {n}
Количество повторений символа можно указать с помощью числа в фигурных скобках: `{n}`.
Такое указание называют *квантификатором* (от англ. quantifier).
У него есть несколько подформ записи:
<dl>
<dt>Точное количество: `{5}`</dt>
<dd>Регэксп <code class="pattern">\d{5}</code> обозначает ровно 5 цифр, в точности как <code class="pattern">\d\d\d\d\d</code>.
Следующий пример находит пятизначное число.
```js
//+ run
alert( "Мне 12345 лет".match (/\d{5}/) ); // "12345"
```
</dd>
<dt>Количество от-до: `{3,5}`</dt>
<dd>Для того, чтобы найти, например, числа размером от трёх до пяти знаков, нужно указать границы в фигурных скобках: <code class="pattern">\d{3,5}</code>
```js
//+ run
alert( "Мне не 12, а 1234 года".match( /\d{3,5}/ ) ); // "1234"
```
Последнее значение можно и не указывать. Тогда выражение <code class="pattern">\d{3,}</code> найдет числа, длиной от трех цифр:
```js
//+ run
alert( "Мне не 12, а 345678 лет".match( /\d{3,5}/ ) ); // "345678"
```
</dd>
</dl>
В случае с телефоном нам нужны числа -- одна или более цифр подряд. Этой задаче соответствует регулярное выражение <code class="pattern">\d{1,}</code>:
```js
//+ run
var str = "+7(903)-123-45-67";
alert( str.match( /\d{1,}/g ) ); // 7,903,123,45,67
```
## Короткие обозначения
Для самые часто востребованных квантификаторов есть специальные короткие обозначения.
[cut]
<dl>
<dt>`+`</dt>
<dd>Означает "один или более", то же что `{1,}`.
@ -20,11 +72,13 @@ alert( str.match( /\d+/g ) ); // 7,903,123,45,67
<dt>`?`</dt>
<dd>Означает "ноль или один", то же что и `{0,1}`. По сути, делает символ необязательным.
Например, <code class="pattern">ou?r</code> найдёт <code class="match">or</code> в слове <code class="subject">color</code> и <code class="match">our</code> в его британском варианте написания <code class="subject">colour</code>.
Например, регэксп <code class="pattern">ou?r</code> найдёт <code class="match">o</code>, после которого, возможно, следует <code class="match">u</code>, а затем <code class="match">r</code>.
Этот регэксп найдёт <code class="match">or</code> в слове <code class="subject">color</code> и <code class="match">our</code> в <code class="subject">colour</code>:
```js
//+ run
var str = "Можно писать color или colour";
var str = "Можно писать color или colour (британский вариант)";
alert( str.match( /colou?r/g ) ); // color, colour
```
@ -50,19 +104,22 @@ alert( "100 10 1".match( /\d0+/g ) ); // 100, 10
</dd>
</dl>
Эти квантификаторы -- одни из важнейших "строительных блоков" для сложных регулярных выражений, поэтому мы рассмотрим ещё примеры.
## Ещё примеры
Эти квантификаторы принадлежат к числу самых важных "строительных блоков" для сложных регулярных выражений, поэтому мы рассмотрим ещё примеры.
<dl>
<dt>Десятичная дробь (число с точкой внутри): <code class="pattern">\d+\.\d+</code></dt>
<dt>Регэксп "десятичная дробь" (число с точкой внутри): <code class="pattern">\d+\.\d+</code></dt>
<dd>
В действии:
```js
//+ run
alert( "0 1 12.345 7890".match( /\d+\.\d+/g ) ); // 123.45
```
</dd>
<dt>Открывающий HTML-тег без атрибутов, такой как `<span>` или `<p>`: <code class="pattern">/&lt;[a-z]+&gt;/i</code></dt>
<dt>Регэксп "открывающий HTML-тег без атрибутов", такой как `<span>` или `<p>`: <code class="pattern">/&lt;[a-z]+&gt;/i</code></dt>
<dd>Пример:
```js
@ -72,7 +129,7 @@ alert( "<BODY> ... </BODY>".match ( /<[a-z]+>/gi ) ); // <BODY>
Это регулярное выражение ищет символ <code class="pattern">'&lt;'</code>, за которым идут одна или более букв английского алфавита, и затем <code class="pattern">'&gt;'</code>.
</dd>
<dt>Открывающий HTML-тег без атрибутов (лучше): <code class="pattern">/&lt;[a-z][a-z0-9]*&gt;/i</code></dt>
<dt>Регэксп "открывающий HTML-тег без атрибутов" (лучше): <code class="pattern">/&lt;[a-z][a-z0-9]*&gt;/i</code></dt>
<dd>
Здесь регулярное выражение расширено: в соответствие со стандартом, HTML-тег может иметь символ на любой позиции, кроме первой, например `<h1>`.
@ -82,7 +139,7 @@ alert( "<h1>Привет!</h1>".match( /<[a-z][a-z0-9]*>/gi ) ); // <h1>
```
</dd>
<dt>Открывающий или закрывающий HTML-тег без атрибутов: <code class="pattern">/&lt;\/?[a-z][a-z0-9]*&gt;/i</code></dt>
<dt>Регэксп "открывающий или закрывающий HTML-тег без атрибутов": <code class="pattern">/&lt;\/?[a-z][a-z0-9]*&gt;/i</code></dt>
<dd>В предыдущий паттерн добавили необязательный слэш <code class="pattern">/?</code> перед тегом. Его понадобилось заэкранировать, чтобы JavaScript не принял его за конец шаблона.
```js
@ -95,13 +152,11 @@ alert( "<h1>Привет!</h1>".match( /<\/?[a-z][a-z0-9]*>/gi ) ); // <h1>, </
[smart header="Точнее -- значит сложнее"]
Здесь мы видим классическую ситуацию, которая повторяется из раза в раз.
Чем точнее регулярное выражение, тем оно длиннее и сложнее.
В этих примерах мы видим общее правило, которое повторяется из раза в раз: чем точнее регулярное выражение, тем оно длиннее и сложнее.
Например, для HTML-тегов, скорее всего, подошло бы и более короткое регулярное выражение <code class="pattern">&lt;\w+&gt;</code>.
Так как класс `\w` означает "любая цифра или английская буква или _`, то под такой шаблон подойдут и не теги, например <code class="match">&lt;_&gt;</code>, однако он гораздо проще, чем <code class="pattern">&lt;[a-z][a-z0-9]*&gt;</code>.
Так как класс `\w` означает "любая цифра или английская буква или `'_'`, то под такой регэксп подойдут и не теги, например <code class="match">&lt;_&gt;</code>. Однако он гораздо проще, чем более точный регэксп <code class="pattern">&lt;[a-z][a-z0-9]*&gt;</code>.
Подойдёт ли нам <code class="pattern">&lt;\w+&gt;</code> или нужно использовать именно <code class="pattern">&lt;[a-z][a-z0-9]*&gt;</code>?

View file

@ -1,13 +1,18 @@
# Жадный и ленивый режимы
# Жадные и ленивые квантификаторы [todo]
Теперь время залезть "под капот" регулярных выражений и посмотреть, как происходит поиск.
Квантификаторы -- с виду очень простая, но на самом деле очень хитрая штука.
Необходимо очень хорошо понимать, как именно происходит поиск, если конечно мы хотим искать что-либо сложнее чем <code class="pattern">/\d+/</code>.
Это понимание необходимо для того, чтобы искать что-либо сложнее чем <code class="pattern">/\d+/</code>.
[cut]
Для примера рассмотрим задачу, которая часто возникает в типографике -- заменить кавычки вида `"..."` на "кавычки-лапки": `«...»`.
Для примера рассмотрим задачу, которая часто возникает в типографике -- заменить в тексте кавычки вида `"..."` (их называют "английские кавычки") на "кавычки-ёлочки": `«...»`.
Шаблон, который мы будем использовать для поиска подстрок в кавычках, будет выглядеть так:
Для этого нужно сначала найти все слова в таких кавычках.
Соотверствующее регулярное выражение может выглядеть так: <code class="pattern">/".+"/g</code>, то есть мы ищем кавычку, после которой один или более произвольный символ, и в конце опять кавычка.
Однако, если попробовать применить его на практике, даже на таком простом случае...
```js
//+ run
@ -15,38 +20,48 @@ var reg = /".+"/g;
var str = 'a "witch" and her "broom" is one';
alert( str.match(reg) );
alert( str.match(reg) ); // "witch" and her "broom"
```
Запустите этот пример...
...Мы увидим, что оно работает совсем не так, как задумано!
Упс! Он не работает! Вместо того, чтобы найти два совпадения <code class="match">"witch"</code> и <code class="match">"broom"</code>, он находит одно: <code class="match">"witch" and her "broom"</code>.
Вместо того, чтобы найти два совпадения <code class="match">"witch"</code> и <code class="match">"broom"</code>, оно находит одно: <code class="match">"witch" and her "broom"</code>.
Это как раз тот случай, когда *жадность* -- причина всех зол.
## Алгоритм поиска
## Жадный поиск
Движок регулярных выражений пытается проверить строку на соответствие шаблону, начиная с самой первой, нулевой позиции. Если не получается, он идёт вперёд и пытается найти с 1й позиции и так далее.
Чтобы найти совпадение, движок регулярных выражений обычно использует следующий алгоритм:
Чтобы сделать происходящее максимально наглядным и понятным, проследим, что именно он делает для паттерна <code class="pattern">".+"</code>.
<ul>
<li>Для каждой позиции в поисковой строке
<ul>
<li>Проверить совпадение на данной позиции
<ul><li>Посимвольно, с учётом классов и квантификаторов сопоставив с ней регулярное выражение.</li></ul>
</li>
</ul>
</li>
</ul>
Это общие слова, гораздо понятнее будет, если мы проследим, что именно он делает для регэкспа <code class="pattern">".+"</code>.
<ol>
<li>Первый символ шаблона -- это кавычка <code class="pattern">"</code>.
Движок регулярных выражений пытается найти её на 0й позиции, но там совсем другой символ, поэтому на 0й позиции соответствия явно нет.
Движок регулярных выражений пытается сопоставить её на 0й позиции в строке, но символ `a`, поэтому на 0й позиции соответствия явно нет.
Далее он переходит 1ю, 2ю позицию в исходной строке и, наконец, обнаруживает кавычку на 3й позиции:
<img src="witch_greedy1.png">
<img src="witch_greedy1.svg">
</li>
<li>Кавычка найдена, далее движок проверяет, есть ли соответствие для остальной части паттерна.
В данном случае следующий символ паттерна -- `.` (точка). Она обозначает "любой символ", так что следующая буква строки <code class="match">'w'</code> вполне подходит:
<img src="witch_greedy2.png">
<img src="witch_greedy2.svg">
</li>
<li>Далее "любой символ" повторяется, так как стоит квантификатор <code class="pattern">.+</code>. Движок регулярных выражений берёт один символ за другим, до тех пор, пока у него это получается.
В данном случае это означает "до конца строки":
<img src="witch_greedy3.png">
<img src="witch_greedy3.svg">
</li>
<li>Итак, текст закончился, движок регулярных выражений больше не может найти "любой символ", он закончил строить соответствие для <code class="pattern">.+</code> и очень рад по этому поводу.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy1.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy1.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;-----------------" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> " </tspan>
<tspan x="72.78125" y="47" fill="#B8BAC1"> </tspan>
<tspan x="85.9765625" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="15" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy2.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy2.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;.----------------" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> ".</tspan>
<tspan x="72.78125" y="47" fill="#B8BAC1"> </tspan>
<tspan x="85.9765625" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="29" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy3.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy3.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;................." sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> "......................</tspan>
<tspan x="349.882812" y="47" fill="#D7343F">.......</tspan>
<tspan x="442.25" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="402" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy4.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy4.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;................." sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> "......................</tspan>
<tspan x="349.882812" y="47" fill="#D7343F">......</tspan>
<tspan x="429.054688" y="47" fill="#B9BAC1">"</tspan>
<tspan x="442.25" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="384" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 579 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy5.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy5.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;................." sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> "......................</tspan>
<tspan x="349.882812" y="47" fill="#D7343F">.....</tspan>
<tspan x="415.859375" y="47" fill="#B9BAC1">".</tspan>
<tspan x="442.25" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="371" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_greedy6.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_greedy6.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;................." sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> "....................."</tspan>
<tspan x="349.882812" y="47" fill="#B9BAC1">.......</tspan>
<tspan x="442.25" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="306" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_lazy3.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_lazy3.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;.&quot;---------------" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> ".</tspan>
<tspan x="72.78125" y="47" fill="#B8BAC1">"</tspan>
<tspan x="85.9765625" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="29" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 579 B

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_lazy4.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_lazy4.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;..&quot;--------------" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal">
<tspan x="20" y="47" fill="#CB1E31"> "..</tspan>
<tspan x="85.9765625" y="47" fill="#B8BAC1">"</tspan>
<tspan x="99.171875" y="47" fill="#CB1E31"> </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="41" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="463px" height="117px" viewBox="0 0 463 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: bin/sketchtool 1.3 (252) - http://www.bohemiancoding.com/sketch -->
<title>witch_lazy6.svg</title>
<desc>Created with bin/sketchtool.</desc>
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="witch_lazy6.svg" sketch:type="MSArtboardGroup">
<text id="a-&quot;witch&quot;-and-her-&quot;b" sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#8A704D">
<tspan x="20" y="82">a "witch" and her "broom" is one</tspan>
</text>
<text id="--&quot;.....&quot;---------&quot;." sketch:type="MSTextLayer" font-family="Consolas" font-size="24" font-weight="normal" fill="#CB1E31">
<tspan x="20" y="47"> "....." "....." </tspan>
</text>
<rect id="Rectangle-1" stroke="#E8C48E" sketch:type="MSShapeGroup" x="45" y="20" width="95" height="77"></rect>
<rect id="Rectangle-2" stroke="#E8C48E" sketch:type="MSShapeGroup" x="256" y="20" width="95" height="77"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB