This commit is contained in:
Ilya Kantor 2017-03-20 20:52:29 +03:00
parent 1e2b09b6fb
commit 7ddea43ab4
22 changed files with 382 additions and 343 deletions

View file

@ -1,33 +1,33 @@
Сначала неправильный способ.
Если перечислить языки один за другим через `|`, то получится совсем не то:
The first idea can be to list the languages with `|` in-between.
But that doesn't work right:
```js run
var reg = /Java|JavaScript|PHP|C|C\+\+/g;
let reg = /Java|JavaScript|PHP|C|C\+\+/g;
var str = "Java, JavaScript, PHP, C, C++";
let str = "Java, JavaScript, PHP, C, C++";
alert( str.match(reg) ); // Java,Java,PHP,C,C
```
Как видно, движок регулярных выражений ищет альтернации в порядке их перечисления. То есть, он сначала смотрит, есть ли `match:Java`, а если нет -- ищет `match:JavaScript`.
The regular expression engine looks for alternations one-by-one. That is: first it checks if we have `match:Java`, otherwise -- looks for `match:JavaScript` and so on.
Естественно, при этом `match:JavaScript` не будет найдено никогда.
As a result, `match:JavaScript` can never be found, just because `match:Java` is checked first.
То же самое -- с языками `match:C` и `match:C++`.
The same with `match:C` and `match:C++`.
Есть два решения проблемы:
There are two solutions for that problem:
1. Поменять порядок, чтобы более длинное совпадение проверялось первым: `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Соединить длинный вариант с коротким: `pattern:Java(Script)?|C(\+\+)?|PHP`.
1. Change the order to check the longer match first: `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Merge variants with the same start: `pattern:Java(Script)?|C(\+\+)?|PHP`.
В действии:
In action:
```js run
var reg = /Java(Script)?|C(\+\+)?|PHP/g;
let reg = /Java(Script)?|C(\+\+)?|PHP/g;
var str = "Java, JavaScript, PHP, C, C++";
let str = "Java, JavaScript, PHP, C, C++";
alert( str.match(reg) ); // Java,JavaScript,PHP,C,C++
```

View file

@ -1,6 +1,11 @@
# Найдите языки программирования
# Find programming languages
Существует много языков программирования, например Java, JavaScript, PHP, C, C++.
There are many programming languages, for instance Java, JavaScript, PHP, C, C++.
Напишите регулярное выражение, которое найдёт их все в строке "Java JavaScript PHP C++ C"
Create a regexp that finds them in the string `subject:Java JavaScript PHP C++ C`:
```js
let reg = /your regexp/g;
alert("Java JavaScript PHP C++ C".match(reg)); // Java JavaScript PHP C++ C
```

View file

@ -1,17 +1,17 @@
Решение задачи: `pattern:/"(\\.|[^"\\])*"/g`.
The solution: `pattern:/"(\\.|[^"\\])*"/g`.
То есть:
Step by step:
- Сначала ищем кавычку `pattern:"`
- Затем, если далее слэш `pattern:\\` (удвоение слэша -- техническое, для вставки в регэксп, на самом деле там один слэш), то после него также подойдёт любой символ (точка).
- Если не слэш, то берём любой символ, кроме кавычек (которые будут означать конец строки) и слэша (чтобы предотвратить одинокие слэши, сам по себе единственный слэш не нужен, он должен экранировать какой-то символ) `pattern:[^"\\]`
- ...И так жадно, до закрывающей кавычки.
- First we look for an opening quote `pattern:"`
- Then if we have a backslash `pattern:\\` (we technically have to double it in the pattern, because it is a special character, so that's a single backslash in fact), then any character is fine after it (a dot).
- Otherwise we take any character except a quote (that would mean the end of the string) and a backslash (to prevent lonely backslashes, the backslash is only used with some other symbol after it): `pattern:[^"\\]`
- ...And so on till the closing quote.
В действии:
In action:
```js run
var re = /"(\\.|[^"\\])*"/g;
var str = '.. "test me" .. "Скажи \\"Привет\\"!" .. "\\r\\n\\\\" ..';
let reg = /"(\\.|[^"\\])*"/g;
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';
alert( str.match(re) ); // "test me","Скажи \"Привет\"!","\r\n\\"
alert( str.match(reg) ); // "test me","Say \"Hello\"!","\\ \""
```

View file

@ -1,25 +1,32 @@
# Найдите строки в кавычках
# Find quoted strings
Найдите в тексте при помощи регэкспа строки в двойных кавычках `subject:"..."`.
Create a regexp to find strings in double quotes `subject:"..."`.
В строке поддерживается экранирование при помощи слеша -- примерно в таком же виде, как в обычных строках JavaScript. То есть, строка может содержать любые символы, экранированные слэшем, в частности: `subject:\"`, `subject:\n`, и даже сам слэш в экранированном виде: `subject:\\`.
The important part is that strings should support escaping, in the same way as JavaScript strings do. For instance, quotes can be inserted as `subject:\"` a newline as `subject:\n`, and the slash itself as `subject:\\`.
Здесь особо важно, что двойная кавычка после слэша не оканчивает строку, а считается её частью. В этом и состоит основная сложность задачи, которая без этого условия была бы элементарной.
Пример совпадающих строк:
```js
.. *!*"test me"*/!* .. (обычная строка)
.. *!*"Скажи \"Привет\"!"*/!* ... (строка с кавычками внутри)
.. *!*"\r\n\\"*/!* .. (строка со спец. символами и слэшем внутри)
let str = "Just like \"here\".";
```
Заметим, что в JavaScript такие строки удобнее всего задавать в одинарных кавычках, и слеши придётся удвоить (в одинарных кавычках они являются экранирующими символами):
For us it's important that an escaped quote `subject:\"` does not end a string.
So we should look from one quote to the other ignoring escaped quotes on the way.
That's the essential part of the task, otherwise it would be trivial.
Examples of strings to match:
```js
.. *!*"test me"*/!* ..
.. *!*"Say \"Hello\"!"*/!* ... (escaped quotes inside)
.. *!*"\\"*/!* .. (double slash inside)
.. *!*"\\ \""*/!* .. (double slash and an escaped quote inside)
```
In JavaScript we need to double the slashes to pass them right into the string, like this:
Пример задания тестовой строки в JavaScript:
```js run
var str = ' .. "test me" .. "Скажи \\"Привет\\"!" .. "\\r\\n\\\\" .. ';
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';
// эта строка будет такой:
alert(str); // .. "test me" .. "Скажи \"Привет\"!" .. "\r\n\\" ..
// the in-memory string
alert(str); // .. "test me" .. "Say \"Hello\"!" .. "\\ \"" ..
```

View file

@ -1,17 +1,16 @@
Начало шаблона очевидно: `pattern:<style`.
The pattern start is obvious: `pattern:<style`.
А вот дальше... Мы не можем написать просто `pattern:<style.*?>`, так как `match:<styler>` удовлетворяет этому регэкспу.
...But then we can't simply write `pattern:<style.*?>`, because `match:<styler>` would match it.
Нужно уточнить его. После `match:<style` должен быть либо пробел, после которого может быть что-то ещё, либо закрытие тега.
We need either a space after `match:<style` and then optionally something else or the ending `match:>`.
На языке регэкспов: `pattern:<style(>|\s.*?>)`.
In the regexp language: `pattern:<style(>|\s.*?>)`.
В действии:
In action:
```js run
var re = /<style(>|\s.*?>)/g;
let reg = /<style(>|\s.*?>)/g;
alert( "<style> <styler> <style test>".match(re) ); // <style>, <style test>
alert( '<style> <styler> <style test="...">'.match(reg) ); // <style>, <style test="...">
```

View file

@ -1,14 +1,13 @@
# Найдите тег style
# Find the full tag
Напишите регулярное выражение, которое будет искать в тексте тег `<style>`. Подходят как обычный тег `<style>`, так и вариант с атрибутами `<style type="...">`.
Write a regexp to find the tag `<style...>`. It should match the full tag: it may have no attributes `<style>` or have several of them `<style type="..." id="...">`.
Но регулярное выражение не должно находить `<styler>`!
...But the regexp should not match `<styler>`!
Использование:
For instance:
```js
var re = ваш регэксп
let reg = /your regexp/g;
alert( "<style> <styler> <style test>".match(re) ); // <style>, <style test>
alert( '<style> <styler> <style test="...">'.match(reg) ); // <style>, <style test="...">
```