JS для начинающих. Урок 1.18: Использование регулярных выражений
Метод search объекта String
Это, пожалуй, самый простой и малоинформативный метод объекта String для работы с регулярными выражениями.
Он принимает в качестве параметра регулярное выражение или строку, которая будет к нему преобразована и возвращает позицию подстроки, совпавшей с регулярным выражением или -1, если такой подстроки не нашлось.
var site = "true-coder.ru"; console.log(site.search(/true/)); // 0 console.log(site.search(/coder/)); // 5 console.log(site.search(/something/)); // -1 var code = "console.log(255 == 0xff); // true"; console.log(code.search("\\d{3}")); // 12 console.log(code.search("0x[\\da-f]+")); // 19
В прошлом уроке мы также упоминали про флаги регулярных выражениях. Продемонстрируем использования флага i, который позволяет игнорировать регистр при поиске подстроки.
var jsIgnoreCasePatter = /javascript/i; console.log("I will code javascript for food" .search(jsIgnoreCasePatter)); // 12 console.log("I will code JavaScript for food" .search(jsIgnoreCasePatter)); // 12 |
Обратим внимание на флаг m, который включает режим многострочного поиска. Продемонстрируем его использование.
var multilineText = "first line\nsecond line"; console.log(multilineText.search(/line$/)); // 18 console.log(multilineText.search(/line$/m)); // 16 |
Обратите внимание, на то, что символ $ расценивается как конец всего текста, если флаг m опущен, и как конец строки в противном случае.
Флаг g игнорируется в регулярном выражении, которое передаётся в качестве параметра методу search.
Метод split объекта String
Этот метод служит для разбиения строки на части. В качестве параметра он принимает разделитель, по которому будет производиться разбиение. Разделитель может быть, как и просто строкой, так и регулярным выражением. Для примера, давайте разрежем строку на части по запятым.
var numbers = "1,two,three,4,five"; numbers = numbers.split(','); console.log(numbers); // ["1", "two", "three", "4", "five"] |
Теперь для разбиения строки воспользуемся регулярным выражением.
var numbers = "1, two, three, 4 , five"; numbers = numbers.split(/\s*,\s*/); console.log(numbers); // ["1", "two", "three", "4", "five"] |
При использовании метода split так же можно ограничить количество частей, на которые разбивается строка. Для этого достаточно просто передать их максимальное количество в качестве второго параметра.
var numbers = "1, two, three, 4 , five"; numbers = numbers.split(/\s*,\s*/, 2); console.log(numbers); // ["1", "two"] |
Meтод match объекта String
Этот метод более информативен, чем метод search. В качестве параметра он так же принимает регулярное выражение, или строку, которая к нему преобразуется. Результатом выполнения этого метода служит массив, содержащий результаты поиска. Если в регулярном выражении отсутствует флаг g, то поиск будет вестись только до первого совпадения. Массив результатов в качестве первого элемента будет содержать строку совпавшею со всем регулярным выражением, а в качестве последующих – подстроки, совпадающие с шаблонами в скобках. Так же массив результатов имеет свойство index, содержащие позицию первого совпавшего символа, и свойство input, которое ссылается на строку, в которой выполнялся поиск. Чтобы продемонстрировать это, давайте напишем функцию, которая выводит информацию о математическом выражении, и воспользуемся ей пару раз.
var expressionPattern = /(\d+)\s*([\+\*\-\/])\s*(\d+)/, additionExpression = "addition: 2 + 2", subtractionExpression = "subsraction: 50 - 4"; function showExpressionInfo(expression) { var matches = expression.match(expressionPattern); /* * Строка, совпавшая с регулярным выражением. * В нашем случае математическое выражение. */ console.log("Expression: " + matches[0]); // Первый аргумент выражения (первые скобки (\d+)) console.log("a = " + matches[1]); // Второй аргумент выражения (третьи скобки (\d+)) console.log("b = " + matches[3]); // Знак математической операции (вторые скобки ([\+\*\-\/])) console.log("sign: " + matches[2]); console.log("index: " + matches.index); console.log("input: " + matches.input); } /* * Expression: 2 + 2 * a = 2 * b = 2 * sign: + * index: 10 * input: addition: 2 + 2 */ showExpressionInfo(additionExpression); /* * Expression: 50 - 4 * a = 50 * b = 4 * sign: - * index: 13 * input: subsraction: 50 - 4 */ showExpressionInfo(subtractionExpression); |
Если в регулярном выражении присутствует флаг g, то поиск осуществляется по всей строке и массив результатов содержит все подстроки, совпавшие с регулярным выражением, за исключением подстрок совпадающих с регулярными выражениями в скобках. Свойства index и input в этом случае у массива результатов отсутствуют.
var expressionPattern = /(\d+)\s*([\+\*\-\/])\s*(\d+)/g, math = "5 + 5 = ?; 10 - 3 = ?; 5 * 6 = ?; 8 / 2 = ?", matches = math.match(expressionPattern); console.log(matches); // ["5 + 5", "10 - 3", "5 * 6", "8 / 2"] |
Если подстрок удовлетворяющим регулярному выражению в строке не найдено, то метод возвращает null.
var str = "violets are blue"; console.log(str.match(/\d/)); // null |
Метод replace объекта String
Этот метод служит для поиска с заменой. В качестве первого аргумента он принимает регулярное выражение, а в качестве второго строку замены. Если у регулярного выражения установлен флаг g, то метод заменяет все найденные совпадения, а в противном случае только первое.
var str = "Baby, I know js. Js is very fun!"; // Baby, I know JavaScript. Js is very fun! console.log(str.replace(/js/, "JavaScript")); // Baby, I know JavaScript. JavaScript is very fun! console.log(str.replace(/js/ig, "JavaScript")); |
Так же обратите внимание на присутствие во втором случаем флага i. Без него второе упоминание js не было бы найдено в строке.
Если в строке замены присутствует знак $ cо следующим за ним номером подвыражения в скобках, то метод replace заменяет эти символы на совпавшую с подвыражением строку. В качестве примера давайте поменяем местами операнды в строке с математическими выражениями.
var expressionPatter = /(\d+)(\s*[\+\*]\s*)(\d+)/g, expressions = "2 + 4, 3+5, 7 * 8"; // 4 + 2, 5+3, 8 * 7 console.log(expressions.replace(expressionPatter, "$3$2$1")); |
Самый интересный случай использования этого метода, это когда в качестве второго аргумента передаётся функция замены. Эта функция в качестве первого параметра принимает совпавшую с регулярным выражением подстроку, затем следуют аргументы, которые содержат строки, совпавшие с подвыражениями в скобках, а в качестве последних двух аргументов функция принимает позицию первого совпавшего символа и строку, в которой производится замена.
var expressionsPattern = /(\d+)\s*([\+\-])\s*(\d+)/g, expressions = "2 + 4, 5-3, 7 + 8", calcAndReplace = function (str, a, operation, b, pos, s) { /* * str - совпавшая подстрока. * В нашем случае это "2 + 4", "5-3" и "7 + 8" * * pos - позиция первого символа совпавшей подстроки. * В нашем случае 0, 7 и 12. * * s - исходная строка, в которой производится замена * Не меняется в ходе замены! */ var a = parseInt(a), b = parseInt(b); if (operation == '+') { return a + b; } else if (operation == '-') { return a - b; } }, results; results = expressions.replace(expressionsPattern, calcAndReplace); console.log(results); // 6, 2, 15 |
Свойства объекта RegExp
У объекта RegExp есть пять свойств. Три из них содержат логические значения, которые свидетельствуют о наличии, или отсутствии у регулярного выражения флагов. Это свойства: ignoreCase, global и multiline. Имена соответствующих им флагов — это первая буква этих свойств. Давайте напишем код, который это демонстрирует.
var withoutFlags = /regexp/, withIFlag = /regexp/i, withGFlag = /regexp/g, withMFlag = /regexp/m, withIGFlag = /regexp/ig, withAllFlags = /regexp/igm; function showFlagInfo(regExp) { var info = 'i: ' + regExp.ignoreCase + '; g: ' + regExp.global + '; m: ' + regExp.multiline; console.log(info); } // i: false; g: false; m: false showFlagInfo(withoutFlags); // i: true; g: false; m: false showFlagInfo(withIFlag); // i: false; g: true; m: false showFlagInfo(withGFlag); // i: false; g: false; m: true showFlagInfo(withMFlag); // i: true; g: true; m: false showFlagInfo(withIGFlag); // i: true; g: true; m: true showFlagInfo(withAllFlags); |
У объекта RegExp так же есть свойство source, доступное только для чтения, в котором лежит строка с регулярным выражением.
var digits = /\d+/; console.log(digits.source); // \d+ digits.source = 'anotherRegExp'; console.log(digits.source); // \d+ |
И последние свойство объекта RegExp это свойство lastIndex, которое содержит индекс последней совпавшей с регулярным выражением подстроки. О нём мы поговорим далее.
Метод exec объекта RegExp
Этот метод аналогичен методу match объекта String, за исключением того, что это метод объекта RegExp, принимающий в качестве параметра строку, а не метод объекта String, принимающий в качестве параметра регулярное выражение. Так же, в отличие от match, этот метод всегда, вне зависимости от того установлен ли флаг g, возвращает массив, нулевым элементом которого является подстрока, совпавшая с регулярным выражением, а последующие элементы этого массива это строки, совпавшие с частями регулярного выражения в скобках. Возвращаемый массив полностью аналогичен тому, что возвращает метод match объекта String. У него так же присутствуют свойстваinput и index.
var expressionPattern = /(\d+)\s*([\+\*\-\/])\s*(\d+)/, additionExpression = "addition: 2 + 2", subtractionExpression = "subsraction: 50 - 4"; function showExpressionInfo(expression) { var matches = expressionPattern.exec(expression) /* * Строка, совпавшая с регулярным выражением. * В нашем случае математическое выражение. */ console.log("Expression: " + matches[0]); // Первый аргумент выражения (первые скобки (\d+)) console.log("a = " + matches[1]); // Второй аргумент выражения (третьи скобки (\d+)) console.log("b = " + matches[3]); // Знак математической операции (вторые скобки ([\+\*\-\/])) console.log("sign: " + matches[2]); console.log("index: " + matches.index); console.log("input: " + matches.input); } /* * Expression: 2 + 2 * a = 2 * b = 2 * sign: + * index: 10 * input: addition: 2 + 2 */ showExpressionInfo(additionExpression); /* * Expression: 50 - 4 * a = 50 * b = 4 * sign: - * index: 13 * input: subsraction: 50 - 4 */ showExpressionInfo(subtractionExpression); |
Однако наличие флага g в регулярном выражении всё-таки влияет на поведение метода exec. При отсутствии этого флага метод всегда оставляет свойство lastIndex регулярного выражения равным нулю. Если же этот флаг установлен, то в этом свойстве находится позиция последнего совпавшего с регулярным выражением символа. С этой позиции начнётся поиск, когда метод exec будет вновь вызван для этого же регулярного выражения.
var str = "Baby, I know js. Js is very fun!",, jsPatternWithGFlag = /js/ig; // ["js", index: 13, input: "Baby, I know js. Js is very fun!"] console.log(jsPatternWithGFlag.exec(str)); // 15 console.log(jsPatternWithGFlag.lastIndex); // ["Js", index: 17, input: "Baby, I know js. Js is very fun!"] console.log(jsPatternWithGFlag.exec(str)); // 19 console.log(jsPatternWithGFlag.lastIndex); |
Обратите внимание, что свойство lastIndex доступно для записи, что позволяет самому задать позицию, с которой будет производиться поиск совпадений.
var str = "Baby, I know js. Js is very fun!", jsPatternWithGFlag = /js/ig; jsPatternWithGFlag.lastIndex = 15; // ["Js", index: 17, input: "Baby, I know js. Js is very fun!"] console.log(jsPatternWithGFlag.exec(str)); // 19 console.log(jsPatternWithGFlag.lastIndex); |
Метод test объекта RegExp
Этот метод существует для проверки соответствуют ли строка регулярному выражению. Он возвращает true, если строка соответствует регулярному выражению и false в противном случае.
var strOne = "Rock'n'roll heaven 24/7", strTwo = "Roses are red", digitPattern = /\d/; console.log(digitPattern.test(strOne)); // true console.log(digitPattern.test(strTwo)); // false |
Этот метод также устанавливает свойство lastIndex если регулярное выражение имеет флаг g, и при следующем его вызове проверка совпадения начинается с новой позиции.
var str = '2 литра "Жигулёвского" и пачку "Винстона", пожалуйста', digitPattern = /\d/g; digitPattern.test(str); // true console.log(digitPattern.lastIndex); // 1 digitPattern.test(str); // false |
Объект RegExp и литералы регулярных выражений
Как упоминалось ранее, регулярные выражения можно создавать двумя способами: при помощи литералов регулярных выражений и при помощи конструктора объекта RegExp. Разные браузеры по-разному ведут себя с литералами регулярных выражений. Большинство современных браузеров создают новый объект RegExp, каждый раз, когда встречается литерал регулярного выражения, но возможно и ситуация, когда объект RegExpсоздаётся единожды в ходе синтаксического анализа. Эти различая очень важны, если вы используете методы объекта RegExp c флагом g и свойствоlastIndex.
На этом пока всё. Как всегда желаю вам успехов!