KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Марейн Хавербеке - Выразительный JavaScript

Марейн Хавербеке - Выразительный JavaScript

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Марейн Хавербеке, "Выразительный jаvascript" бесплатно, без регистрации.
Перейти на страницу:

Выглядит ужасно, не так ли? Слишком много обратных слэшей, которые затрудняют понимание шаблона. Позже мы слегка улучшим его.

Обратные слэши можно использовать и в квадратных скобках. Например, [d.] означает любую цифру или точку. Заметьте, что точка внутри квадратных скобок теряет своё особое значение и превращается просто в точку. То же касается и других специальных символов, типа +.

Инвертировать набор символов – то есть, сказать, что вам надо найти любой символ, кроме тех, что есть в наборе – можно, поставив знак ^ сразу после открывающей квадратной скобки.

var notBinary = /[^01]/;

console.log(notBinary.test("1100100010100110"));

// → false

console.log(notBinary.test("1100100010200110"));

// → true

Повторяем части шаблона

Мы знаем, как найти одну цифру. А если нам надо найти число целиком – последовательность из одной или более цифр?

Если поставить после чего-либо в регулярке знак +, это будет означать, что этот элемент может быть повторён более одного раза. /d+/ означает одну или несколько цифр.

console.log(/'d+'/.test("'123'"));

// → true

console.log(/'d+'/.test("''"));

// → false

console.log(/'d*'/.test("'123'"));

// → true

console.log(/'d*'/.test("''"));

// → true

У звёздочки * значение почти такое же, но она разрешает шаблону присутствовать ноль раз. Если после чего-то стоит звёздочка, то оно никогда не препятствует нахождению шаблона в строке – оно просто находится там ноль раз.

Знак вопроса делает часть шаблона необязательной, то есть она может встретиться ноль или один раз. В следующем примере символ u может встречаться, но шаблон совпадает и тогда, когда его нет.

var neighbor = /neighbou?r/;

console.log(neighbor.test("neighbour"));

// → true

console.log(neighbor.test("neighbor"));

// → true

Чтобы задать точное количество раз, которое шаблон должен встретиться, используются фигурные скобки. {4} после элемента означает, что он должен встретиться в строке 4 раза. Также можно задать промежуток: {2,4} означает, что элемент должен встретиться не менее 2 и не более 4 раз.

Ещё одна версия формата даты и времени, где разрешены дни, месяцы и часы из одной или двух цифр. И ещё она чуть более читаема.

var dateTime = /d{1,2}-d{1,2}-d{4} d{1,2}:d{2}/;

console.log(dateTime.test("30-1-2003 8:45"));

// → true

Можно использовать промежутки с открытым концом, опуская одно из чисел. {,5} означает, что шаблон может встретиться от нуля до пяти раз, а {5,} – от пяти и более.

Группировка подвыражений

Чтобы использовать операторы * или + на нескольких элементах сразу, можно использовать круглые скобки. Часть регулярки, заключённая в скобки, считается одним элементом с точки зрения операторов.

var cartoonCrying = /boo+(hoo+)+/i;

console.log(cartoonCrying.test("Boohoooohoohooo"));

// → true

Первый и второй плюсы относятся только ко вторым буквам o в словах boo и hoo. Третий + относится к целой группе (hoo+), находя одну или несколько таких последовательностей.

Буква i в конце выражения делает регулярку нечувствительной к регистру символов – так, что B совпадает с b.

Совпадения и группы

Метод test – самый простой метод проверки регулярок. Он только сообщает, было ли найдено совпадение, или нет. У регулярок есть ещё метод exec, который вернёт null, если ничего не было найдено, а в противном случае вернёт объект с информацией о совпадении.

var match = /d+/.exec("one two 100");

console.log(match);

// → ["100"]

console.log(match.index);

// → 8

У возвращаемого exec объекта есть свойство index, где содержится номер символа, с которого случилось совпадение. А вообще объект выглядит как массив строк, где первый элемент – строка, которую проверяли на совпадение. В нашем примере это будет последовательность цифр, которую мы искали.

У строк есть метод match, работающий примерно так же.

console.log("one two 100".match(/d+/));

// → ["100"]

Когда в регулярке содержатся подвыражения, сгруппированные круглыми скобками, текст, совпавший с этими группами, тоже появится в массиве. Первый элемент всегда совпадение целиком. Второй – часть, совпавшая с первой группой (той, у кого круглые скобки встретились раньше всех), затем со второй группой, и так далее.

var quotedText = /'([^']*)'/;

console.log(quotedText.exec("she said 'hello'"));

// → ["'hello'", "hello"]

Когда группа не найдена вообще (например, если за ней стоит знак вопроса), её позиция в массиве содержит undefined. Если группа совпала несколько раз, то в массиве будет только последнее совпадение.

console.log(/bad(ly)?/.exec("bad"));

// → ["bad", undefined]

console.log(/(d)+/.exec("123"));

// → ["123", "3"]

Группы полезны для извлечения частей строк. Если нам не просто надо проверить, есть ли в строке дата, а извлечь её и создать представляющий дату объект, мы можем заключить последовательности цифр в круглые скобки и выбрать дату из результата exec.

Но для начала небольшое отступление, в котором мы узнаем предпочтительный способ хранения даты и времени в JavaScript.

Тип даты

В JavaScript есть стандартный тип объекта для дат – а точнее, моментов во времени. Он называется Date. Если просто создать объект даты через new, вы получите текущие дату и время.

console.log(new Date());

// → Sun Nov 09 2014 00:07:57 GMT+0300 (CET)

Также можно создать объект, содержащий заданное время

console.log(new Date(2015, 9, 21));

// → Wed Oct 21 2015 00:00:00 GMT+0300 (CET)

console.log(new Date(2009, 11, 9, 12, 59, 59, 999));

// → Wed Dec 09 2009 12:59:59 GMT+0300 (CET)

JavaScript использует соглашение, в котором номера месяцев начинаются с нуля, а номера дней – с единицы. Это глупо и нелепо. Поберегитесь.

Последние четыре аргумента (часы, минуты, секунды и миллисекунды) необязательны, и в случае отсутствия приравниваются к нулю.

Метки времени хранятся как количество миллисекунд, прошедших с начала 1970 года. Для времени до 1970 года используются отрицательные числа (это связано с соглашением по Unix time, которое было создано примерно в то время). Метод getTime объекта даты возвращает это число. Оно, естественно, большое.

console.log(new Date(2013, 11, 19).getTime());

// → 1387407600000

console.log(new Date(1387407600000));

// → Thu Dec 19 2013 00:00:00 GMT+0100 (CET)

Если задать конструктору Date один аргумент, он будет восприниматься как количество миллисекунд. Текущее значение миллисекунд можно получить, создав объект Date и вызвав метод getTime, или же вызвав функцию Date.now.

У объекта Date для извлечения его компонентов есть методы getFullYear, getMonth, getDate, getHours, getMinutes, и getSeconds. Есть также метод getYear, возвращающий довольно бесполезный двузначный код, типа 93 или 14.

Заключив нужные части шаблона в круглые скобки, мы можем создать объект даты прямо из строки.

function findDate(string) {

  var dateTime = /(d{1,2})-(d{1,2})-(d{4})/;

  var match = dateTime.exec(string);

  return new Date(Number(match[3]),

                  Number(match[2]) - 1,

                  Number(match[1]));

}

console.log(findDate("30-1-2003"));

// → Thu Jan 30 2003 00:00:00 GMT+0100 (CET)

Границы слова и строки

К сожалению, findDate так же радостно извлечёт бессмысленную дату 00-1-3000 из строки "100-1-30000". Совпадение может случиться в любом месте строки, так что в данном случае он просто начнёт со второго символа и закончит на предпоследнем.

Если нам надо принудить совпадение взять всю строку целиком, мы используем метки ^ и $. ^ совпадает с началом строки, а $ – с концом. Поэтому /^d+$/ совпадает со строкой, состоящей только из одной или нескольких цифр, /^!/ совпадает со строкой, начинающейся с восклицательного знака, а /x^/ не совпадает ни с какой строчкой (перед началом строки не может быть x).

Если, с другой стороны, нам просто надо убедиться, что дата начинается и заканчивается на границе слова, мы используем метку b. Границей слова может быть начало или конец строки, или любое место строки, где с одной стороны стоит алфавитно-цифровой символ w, а с другой – не алфавитно-цифровой.

console.log(/cat/.test("concatenate"));

// → true

console.log(/bcatb/.test("concatenate"));

// → false

Отметим, что метка границы не представляет из себя символ. Это просто ограничение, обозначающее, что совпадение происходит только если выполняется определённое условие.

Шаблоны с выбором

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*