Особенности регулярных выражений в Javascript
Регулярные выражения в javascript немного странные. Вроде - перловые, обычные, но с подводными камнями, на которые натыкаются даже опытные javascript-разработчики.
Эта статья ставит целью перечислить неожиданные фишки и особенности RegExp в краткой и понятной форме.
Общую информацию о регулярных выражениях в javascript вы можете найти в статье Регулярные выражения.
Для поиска в многострочном режиме почти все модификации перловых регэкспов используют специальный multiline-флаг.
И javascript здесь не исключение.
Попробуем же сделать поиск и замену многострочного вхождения. Скажем, будем заменять [u] ... [/u] на тэг подчеркивания: <u> :
function bbtagit(text) {
text = text.replace(/\[u\](.*?)\[\/u\]/gim, '<u>$1</u>')
return text
}
var line = "[u]мой\n текст[/u]"
alert( bbtagit(line) )
Попробуйте запустить. Заменяет? Как бы не так!
Дело в том, что в javascript мультилайн режим (флаг m ) влияет только на символы ^ и $, которые начинают матчиться с началом и концом строки, а не всего текста.
Точка по-прежнему - любой символ, кроме новой строки. В javascript нет флага, который устанавливает мультилайн-режим для точки. Для того, чтобы заматчить совсем что угодно - используйте [\s\S] .
Работающий вариант:
function bbtagit(text) {
text = text.replace(/\[u\]([\s\S]*)\[\/u\]/gim, '<u>$1</u>')
return text
}
var line = "[u]мой\n текст[/u]"
alert( bbtagit(line) )
Это не совсем особенность, скорее фича, но все же достойная отдельного абзаца.
Все регулярные выражения в javascript - жадные. То есть, выражение старается отхватить как можно больший кусок строки.
Например, мы хотим заменить все открывающие тэги <a> . На что и почему - не так важно.
text = '1 <A href="#">...</A> 2'
text = text.replace(/<A(.*)>/, 'TEST')
alert(text)
При запуске вы увидите, что заменяется не открывающий тэг, а вся ссылка, выражение матчит ее от начала и до конца.
Это происходит из-за того, что точка-звездочка в "жадном" режиме пытается захватить как можно больше, в нашем случае - это как раз до последнего > .
Последний символ > точка-звездочка не захватывает, т.к. иначе не будет совпадения.
Как вариант решения используют квадратные скобки: [^>] :
text = '1 <A href="#">...</A> 2'
text = text.replace(/<A([^>]*)>/, 'TEST')
alert(text)
Это работает. Но самым удобным вариантом является переключение точки-звездочки в нежадный режим. Это осуществляется простым добавлением знака "? " после звездочки.
В нежадном режиме точка-звездочка пустит поиск дальше сразу, как только нашла совпадение:
text = '1 <A href="#">...</A> 2'
text = text.replace(/<A(.*?)>/, 'TEST')
alert(text)
В некоторых языках программирования можно переключить жадность на уровне всего регулярного выражения, флагом.
В javascript это сделать нельзя.. Вот такая особенность. А вопросительный знак после звездочки рулит - честное слово.
Иногда нужно в самом паттерне поиска обратиться к предыдущей его части.
Например, при поиске BB-тагов, то есть строк вида [u]...[/u] , [b]...[/b] и [s]...[/s] . Или при поиске атрибутов, которые могут быть в одинарных кавычках или двойных.
Обращение к предыдущей части паттерна в javascript осуществляется как \1, \2 и т.п., бэкслеш + номер скобочной группы:
text = ' [b]a [u]b[/u] c [/b] '
var reg = /\[([bus])\](.*?)\[\//*u*/\1/*/u*/\]/
text = text.replace(reg, '<$1>$2</$1>')
alert(text)
Обращение к скобочной группе в строке замены идет уже через доллар: $1 . Не знаю, почему, наверное так удобнее..
P.S. Понятно, что при таком способе поиска bb-тагов придется пропустить текст через замену несколько раз - пока результат не перестанет отличаться от оригинала.
Эти две задачи решаются в javascript принципиально по-разному.
Начнем с "простого".
Для замены всех вхождений используется метод String#replace.
Он интересен тем, что допускает первый аргумент - регэксп или строку.
Если первый аргумент - строка, то будет осуществлен поиск подстроки, без преобразования в регулярное выражение.
Попробуйте:
alert("2 ++ 1".replace("+", "*"))
Каков результат? Как, заменился только один плюс, а не два? Да, вот так.
Чтобы заменить все вхождения, String#replace придется использовать в режиме регулярного выражения.
В режиме регулярного выражения плюс придется заэкранировать, но зато replace заменит все вхождения (при указании флага g ):
alert("2 ++ 1".replace(/\+/g, "*"))
Вот такая особенность работы со строкой.
Очень полезной особенностью replace является возможность работать с функцией вместо строки замены. Такая функция получает первым аргументом - все совпадение, а последующими аргументами - скобочные группы.
Следующий пример произведет операции вычитания:
var str = "count 36 - 26, 18 - 9"
str = str.replace(/(\d+) - (\d+)/g, function(a,b,c) { return b-c })
alert(str)
В javascript нет одного универсального метода для поиска всех совпадений.
Для поиска без запоминания скобочных групп - можно использовать String#match:
var str = "count 36-26, 18-9"
var re = /(\d+)-(\d+)/g
result = str.match(re)
for(var i=0; i<result.length; i++) alert(result[i])
Как видите, оно исправно ищет все совпадения (флаг 'g' у регулярного выражения обязателен), но при этом не запоминает скобочные группы. Эдакий "облегченный вариант".
В сколько-нибудь сложных задачах важны не только совпадения, но и скобочные группы. Чтобы их найти, предлагается использовать многократный вызов RegExp#exec.
Для этого регулярное выражение должно использовать флаг 'g' . Тогда результат поиска, запомненный в свойстве lastIndex объекта RegExp используется как точка отсчета для следующего поиска:
var str = "count 36-26, 18-9"
var re = /(\d+)-(\d+)/g
var res
while ( (res = re.exec(str)) != null) {
alert("Найдено " + res[0] + ": ("+ res[1]+") и ("+res[2]+")")
alert("Дальше ищу с позиции "+re.lastIndex)
}
Проверка while( (res = re.exec(str)) != null) нужна т.к. значение res = 0 является хорошим и означает, что вхождение найдено в самом начале строки (поиск успешен). Поэтому необходимо сравнивать именно с null .
Ну и напоследок - еще одна совсем оригинальная особенность регулярных выражений.
Вот - одна интересная функция.
Запустите ее один раз, запомните результат - и запустите еще раз.
function rere() {
var re1 = /0/, re2 = new RegExp('0')
alert([re1.foo, re2.foo])
re1.foo = 1
re2.foo = 1
}
rere()
В зависимости от браузера, результат первого запуска может отличаться от второго. На текущий момент, это так для Firefox, Opera. При этом в Internet Explorer все нормально.
С виду функция создает две локальные переменные и не зависит от каких-то внешних факторов.
Почему же разный результат?
Ответ кроется в стандарте ECMAScript, пункт 7.8.5:
Цитата...
A regular expression literal is an input element that is converted to a RegExp object (section 15.10)
when it is scanned. The object is created before evaluation of the containing program or function begins.
Evaluation of the literal produces a reference to that object; it does not create a new object.
То есть, простыми словами, литеральный регэксп не создается каждый раз при вызове var r = /regexp/ .
Вместо этого браузер возвращает уже существующий объект, со всеми свойствами, оставшимися от предыдущего запуска.
В отличие от этого, new RegExp всегда создает новый объект, поэтому и ведет себя в примере по-другому.
Есть еще особенности?
Напишите в комментарии, и я добавлю их в статью.
|
พัฒนาระบบมาเป็นระบบออโต้ pg slot เว็บตรง อันดับ1 มาใหม่มาแรงมากที่สุด ในตอนนี้ โปรโมชั่นเน้นๆ จัดเต็มมาให้ผู้ใช้งานได้เล่นกันอย่างเพลิดเพลิด โปรโมชั่น pg slot ระบบมีความปลอดภัยสูงมากที่สุด
คาสิโนออนไลน์ รวมเกมสุดฮิตบนเว็บ pgslot บนมือถือ 24 ชั่วโมง ด้วยระบบออโต้ที่ทันสมัย pg slot ฝาก ถอน เงินด้วยตัวคุณเองง่าย ๆ ไม่มีล่าช้า
Good sharing such valuable information. megagame ล่าสุด
Thank you for sharing such valuable information.
Your website has been a game changer for me, thank you. เมก้าสล็อตล่าสุด
ทางเข้า ยู ฟ่า เบ ท เว็บเดิมพันออนไลน์อันดับ 1 ของเรามีหลากหลายเกม ไม่ว่าจะเป็น เดิมพันกีฬาออนไลน์ บาคาร่าออนไลน์ รูเร็ท เสือมังกร สล็อตออนไลน์ มีระบบ service พร้อมซัฟพอร์ทผู้เล่นตลอด 24 เราจะพาคุณพบสัมผัส
I was impressed by your writing. Your writing is impressive. I want to write like you.카지노게임사이트 I hope you can read my post and let me know what to modify. My writing is in I would like you to visit my blog.
สล็อตแตกง่าย greenx88 2023 เว็บตรงไม่ผ่านเอเยนต์ ที่ได้รับความนิยมอันดับต้น ๆ และเป็นศูนย์รวมเว็บสล็อตออนไลน์อย่างครบถ้วน อยู่ในเว็บไซต์เดียว ดังนั้นหากคุณจะหาเว็บไซต์
สล็อตแตกง่าย greenx88 2023 เว็บตรงไม่ผ่านเอเยนต์ ที่ได้รับความนิยมอันดับต้น ๆ และเป็นศูนย์รวมเว็บสล็อตออนไลน์อย่างครบถ้วน อยู่ในเว็บไซต์เดียว ดังนั้นหากคุณจะหาเว็บไซต์
สล็อตแตกง่าย greenx88 2023 เว็บตรงไม่ผ่านเอเยนต์ ที่ได้รับความนิยมอันดับต้น ๆ และเป็นศูนย์รวมเว็บสล็อตออนไลน์อย่างครบถ้วน อยู่ในเว็บไซต์เดียว ดังนั้นหากคุณจะหาเว็บไซต์
เว็บสล็อตเล่นง่าย ทดลองเล่นฟรี อัพเดทเกมสล็อตใหม่ 2023 สล็อต
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.