До этого момента мы обсуждали грамматику создаваемых регулярных выраже_ ний, но не рассматривали, как эти регулярные выражения могут реально ис_ пользоваться в JavaScript_сценариях. В данном разделе мы обсудим методы объ_
224 Глава 11. Шаблоны и регулярные выражения
екта String, в которых регулярные выражения применяются для поиска по шаб_ лону, а также для поиска и замены. А затем продолжим разговор о поиске по шаблону с регулярными JavaScript_выражениями, рассмотрев объект RegExp, его методы и свойства. Обратите внимание: последующее обсуждение – это лишь об_ зор различных методов и свойств, относящихся к регулярным выражениям. Как обычно, полное описание можно найти в третьей части книги.
Строки поддерживают четыре метода, опирающихся на регулярные выражения. Простейший из них – метод search(). Он принимает в качестве аргумента регу_ лярное выражение и возвращает либо позицию символа в начале первой найден_ ной подстроки, либо –1, если соответствие не найдено. Например, следующий вызов возвращает 4:
"JavaScript".search(/script/i);
Если аргумент метода search() не является регулярным выражением, он сначала преобразуется путем передачи конструктору RegExp. Метод search() не поддержи_ вает глобальный поиск и игнорирует флаг g в своем аргументе.
Метод replace() выполняет операцию поиска с заменой. Он принимает в качестве первого аргумента регулярное выражение, а в качестве второго – строку замены. Метод ищет в строке, для которой он вызван, соответствие указанному шаблону. Если регулярное выражение содержит флаг g, метод replace() заменяет все вхо_ ждения строки строкой замены, в противном случае он заменяет только первое найденное вхождение. Если первый аргумент метода replace() представляет со_ бой не регулярное выражение, а строку, то метод выполняет буквальный поиск строки, а не преобразует ее в регулярное выражение с помощью конструктора RegExp(), как это делает метод search(). В качестве примера мы можем воспользо_ ваться методом replace() для единообразной расстановки прописных букв в сло_ ве «JavaScript» для всей строки текста:
// Независимо от регистра символов заменяем словом в нужном регистре text.replace(/javascript/gi, "JavaScript");
Однако метод replace() представляет собой более мощное средство, чем можно су_ дить по этому примеру. Вспомните, что подвыражения в скобках, находящиеся внутри регулярного выражения, нумеруются слева направо, и что регулярное выражение запоминает текст, соответствующий каждому из подвыражений. Ес_ ли в строке замены присутствует знак $ с цифрой, метод replace() заменяет эти два символа текстом, соответствующим указанному подвыражению. Это очень полезная возможность. Мы можем использовать ее, например, для замены пря_ мых кавычек в строке типографскими кавычками, которые имитируются ASCII_ символами:
// Цитата – это кавычка, за которой следует любое число символов,
// отличных от кавычек (их мы запоминаем), за этими символами следует
// еще одна кавычка.
var quote = /"([^"]*)"/g;
// Заменяем прямые кавычки типографскими и оставляем без
// изменений содержимое цитаты, хранящееся в $1. text.replace(quote, "``$1''");
Метод replace() предоставляет и другие ценные возможности, о которых расска_ зывается в третьей части книги при описании конструкции String.replace(). Са_
11.2. Методы класса String для поиска по шаблону
мое важное, что следует отметить, – второй аргумент replace() может быть функ_ цией, динамически вычисляющей строку замены.
Метод match() – это наиболее общий из методов класса String, опирающихся на регулярные выражения. Он принимает в качестве единственного аргумента ре_ гулярное выражение (или преобразует свой аргумент в регулярное выражение, передав его конструктору RegExp()) и возвращает массив, содержащий результа_ ты поиска. Если в регулярном выражении установлен флаг g, метод возвращает массив всех соответствий, присутствующих в строке. Например:
"1 плюс 2 равно 3".match(/\d+/g) // возвращает ["1", "2", "3"]
Если регулярное выражение не содержит флаг g, метод match() не выполняет гло_ бальный поиск; он просто ищет первое соответствие. Однако match() возвращает массив, даже когда метод не выполняет глобальный поиск. В этом случае пер_ вый элемент массива – это найденная строка, а все оставшиеся элементы пред_ ставляют собой подвыражения регулярного выражения. Поэтому если match() возвращает массив a, то a[0] будет содержать найденную строку целиком, a[1] – подстроку, соответствующую первому подвыражению, и т. д. Проводя парал_ лель с методом replace(), можно сказать, что в a[n] заносится содержимое $n.
В качестве примера рассмотрите следующий программный код, выполняющий разбор URL_адреса:
var url = /(\w+):\/\/([\w.]+)\/(\S*)/;
var text = "Посетите мою домашнюю страницу http://www.isp.com/~david";
var result =
text.match(url);
if (result != null) {
var fullurl = result[0];
// Содержит "http://www.isp.com/~david"
var protocol = result[1];
// Содержит "http"
var host
= result[2];
// Содержит "www.isp.com"
var path
= result[3];
// Содержит "~david"
}
И наконец, имеется еще одна особенность метода match(), о которой следует знать. Возвращаемый им массив имеет, как и все массивы, свойство length. Од_ нако когда match() вызывается с регулярным выражением без флага g, возвра_ щаемый массив имеет еще два свойства: index, содержащее номер позиции сим_ вола внутри строки, с которого начинается соответствие, и input, являющееся копией строки, в которой выполнялся поиск. То есть в приведенном примере значение result.index будет равно 31, т. к. найденный URL_адрес начинается в тексте с 31_й позиции. Свойство result.input должно содержать ту же строку, что и переменная text. Для регулярного выражения r, в котором не установлен флаг g, вызов s.match(r) возвращает то же значение, что и r.exec(s). Немного позднее в этой главе мы обсудим метод RegExp.exec().
Последний из методов объекта String, в котором используются регулярные вы_ ражения, – это split(). Этот метод разбивает строку, для которой он вызван, на массив подстрок, используя аргумент в качестве разделителя. Например:
Метод split() может также принимать в качестве аргумента регулярное выра_ жение. Это делает метод более мощным. Например, мы можем указать раздели_ тель, допускающий произвольное число пробельных символов с обеих сторон: