Введение
Регулярные выражения всем знакомы и незнакомы. Знакомство связано с тем, что в работе есть много сценариев, которые можно использовать, например, номер мобильного телефона, электронная почта, пароль и другие правила проверки.
Незнакомым является то, что регулярное выражение выглядит как набор искаженных символов, и с первого взгляда трудно понять правила сопоставления. Иногда, когда я ищу регулярное выражение для определенного правила в Интернете, результаты другие, а эффект выполнения еще менее удовлетворительный.
Сегодня я потрачу 30 минут на то, чтобы помочь вам проанализировать цель сопоставления с другой точки зрения, понять идею сопоставления и шаг за шагом научиться писать регулярные выражения (читать регулярные выражения гораздо сложнее, чем писать регулярные выражения). ).
2. Поймите, что делать с регулярностью
То, что необходимо сделать, можно резюмировать в виде следующих трех вопросов души:Q1. Что это соответствует? Q2. Что не соответствует? Q3. Сколько раз совпадать?
Q1. Что это соответствует?
Это легко понять, например, если вы хотите сопоставить символ a, напишите его прямо/a/
, если позиция в строке равна a, она может быть сопоставлена:
/a/.test("javascript") //true
Чтобы сопоставить строку, начинающуюся с a, добавьте метасимволы^
(идентификатор стартовой позиции),/^a/
:
/^a/.test("javascript") //不是以a开头返回false
/^a/.test("abc") //是以a开头返回true
Чтобы сопоставить строки, оканчивающиеся на a, добавьте метасимволы$
(идентификатор конечной позиции),/a$/
:
/a$/.test("javascript") //不是以a结尾返回false
/a$/.test("cba") //是以a结尾返回true
Чтобы соответствовать символу a или b, вы можете поместить соответствующий символ в квадратные скобки/[ab]/
, который соответствует до тех пор, пока строка содержит a или b:
/[ab]/.test("byte") //true
соответствует строке abc или xyz,/abc|xyz/
:
/abc|xyz/.test("aabbxyz") //本字符串包含xyz,所以返回true
① Сопоставьте то, что находится перед ним (используйте просмотр вперед)
прогнозное определение
(?=exp)
: соответствует позиции, за которой следует exp
exp1(?=exp2)
: соответствует exp1 перед exp2, результат сопоставления не содержит exp2
Например, чтобы сопоставить часть java перед script в строке,/java(?=script)/
:
/java(?=script)/.test("javascript,javaee,typescript") //字符串中javascript符合规则 会返回ture
//1、用exec方法来验证下匹配的结果
/java(?=script)/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["java", index: 0, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是java,index是0,说明找到了的是javascript中script前面的java
② Сопоставьте, что будет после (используйте после просмотра)
Обратное определение
(?<=exp)
: соответствует позиции, которой предшествует exp
(?<=exp2)exp1
: соответствует exp1 после exp2, результат сопоставления не содержит exp2
Например, чтобы соответствовать ee после java в строке,/(?<=java)ee/
:
/(?<=java)ee/.test("javascript,javaee,typescript") //字符串中javaee符合规则 会返回ture
//1、用exec方法来验证下匹配的结果
/(?<=java)ee/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["ee", index: 15, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是ee,index是15,说明找到了的是javaee中java后面的ee
Q2. Что не соответствует?
Сопоставление ничто, это означает отрицание, пока это не они, оно может сопоставляться.Например, если вы не хотите сопоставлять символ а, обычное написание/[^a]/
, который является метасимволом в квадратных скобках^
, пока строка удовлетворяет символам, которых нет в этом наборе, она может быть сопоставлена:
/[^a]/.test("aaa") //字符串全是a,返回false
/[^a]/.test("abc") //字符串不全是a,返回true
Совпадение не начинается с a, аналогично предыдущему совпадению, плюс метасимволы^
,/^[^a]/
:
/^[^a]/.test("javascript") //此字符串不是以a开头,返回true
/^[^a]/.test("abc") //此字符串是以a开头,返回false
Совпадение не заканчивается на a, оно похоже на предыдущее совпадение, плюс метасимволы$
,/[^a]$/
:
/[^a]$/.test("javascript") //此字符串不是以a结束,返回true
/[^a]$/.test("cba") //此字符串是以a结束,返回false
Не совпадайте с символами a, b, c, вы можете поставить соответствующие символы в квадратных скобках/[^abc]/
:
/[^abc]$/.test("abccba") //此字符串的字符全部都不符合,返回false
① После матча ничего нет (с использованием отрицательного прогноза)
Определение отрицательного просмотра вперед
(?!exp)
: соответствует положению, которое не сопровождается exp
exp1(?!exp2)
: соответствует exp1, за которым не следует exp2, и результат сопоставления не содержит exp2
Например, чтобы сопоставить java, за которым не следует скрипт в строке,/java(?!script)/
:
/java(?!script)/.test("javascript,javaee,typescript") //字符串javaee符合规则 会返回ture
//1、用exec方法来验证下匹配的结果
/java(?!script)/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["java", index: 11, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是java,index是11,说明找到了的是javaee中的java,因为这个java后面是ee
② Сопоставьте то, что не впереди (используйте отрицательный просмотр назад)
отрицательное прогнозное определение
(?<!exp)
: соответствует позиции, которой не предшествует exp
(?<!exp2)exp1
: соответствует exp1, который не является exp2 впереди, и результат сопоставления не содержит exp2
Например, чтобы сопоставить скрипты, которым не предшествует java в строке,/(?<!java)script/
:
/(?<!java)script/.test("javascript,javaee,typescript") //字符串中typescript符合规则 会返回ture
//1、用exec方法来验证下匹配的结果
/(?<!java)script/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["script", index: 22, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是script,index是22,说明找到了的是typescript中type后面的script
③ Совпадение со строками, не содержащими последовательных букв abc.
Это довольно особое поведение при сопоставлении, если только записать его как/[^abc]/
, комплект внутри或
Отношение. Это означает, что строка не может содержатьa
,b
,c
Любой из этих трех не может определить, содержит ли строка последовательныеabc
.
Затем мы должны проанализировать его под другим углом. Abc не может постоянно появляться в любой позиции строки. Мы можем использоватьнегативный взгляд впередфункции, чтобы соответствовать, а затем шаг за шагом реализовать это регулярно:
- За совпадающими позициями не может следовать abc, используйте отрицательный просмотр вперед для сопоставления таких позиций:
/(?!abc)/
- За этой позицией могут следовать другие символы, используйте
\w
Представлять:/(?!abc)\w/
- После выполнения вышеуказанных условий позицию можно использовать несколько раз подряд.
+
для представления количества:/((?!abc)\w)+/
- Чтобы покрыть каждую позицию от начала до конца, добавьте маркеры начала и конца:
/^((?!abc)\w)+$/
/^((?!abc)\w)+$/.test("cbacbac") //本字符串中不包含连续的abc,结果返回true
/^((?!abc)\w)+$/.test("cbacbabc") //本字符串中包含连续的abc,结果返回false
Тут у вас еще может возникнуть вопрос: зачем использоватьнегативный взгляд вперед(Не неловко сзади), не нужнонегативный взгляд(передний не какой), просто проверить, что перед каждой позицией не стоит abc?
Ответ - нет. Поскольку регулярка проверяется с первой позиции строки, начало первой позиции любой строки пусто, поэтому первая строка не удовлетворяет условию, что начало не равно abc, поэтому она не работает.
Однако и этот случай можно использоватьпредвидениеЧтобы определить, содержит ли строка abc, достаточно ввестинегативный взгляд впередкак пользоваться.
Графический взгляд вперед и взгляд назад со значением спереди и сзади
Зеленые символы и позиции на рисунке были сопоставлены и обнаружены, красные в настоящее время сопоставляются и обнаруживаются, серые не сопоставляются и не обнаруживаются, а направление сопоставления — слева направо. Вперед и назад в вперед и назад см.спереди и сзади соответствующего направления, а не до или после позиции строки. Упреждающий и обратный просмотр также называются положительными утверждениями нулевой ширины и отрицательными утверждениями нулевой ширины (нулевая ширина означает только совпадающие символы, которые не соответствуют позициям), где положительные и отрицательные направления также относятся к направлению сопоставления.
Таким образом, просмотр вперед — это просмотр вперед от совпадающей позиции к началу совпадающего направления, чтобы определить, является ли символ впереди выражением; просмотр назад — это просмотр от совпадающей позиции к задней части совпадения, чтобы определить, является ли символ позади - exp; отрицательный просмотр вперед - смотреть вперед, чтобы определить, не является ли персонаж впереди exp; отрицательный просмотр назад - это смотреть назад, чтобы определить, не является ли персонаж позади exp.
Дополнительные замечания:Оглядываясь назадинегативный взглядОн не поддерживается на некоторых языках или в некоторых средах, пожалуйста, внимательно проверяйте поддержку при использовании
Чтобы лучше понять такие точки знаний, как перспективный и ретроспективный, я написал специальную аналитическую статью.Если вам интересно, вы можете прочитать "Одна картинка для просмотра вперед и назад в обычном》
Q3. Сколько раз совпадать?
Соответствие один раз, вы можете сделать что-либо без определения, например соответствующий номер/\d/
, если вы хотите сопоставить три последовательных числа, проще всего написать это три раза подряд:/\d\d\d/
, это не проблема написать таким образом, это может соответствовать правильно.
Но если количество раз слишком много или количество раз неопределенно, это определенно не сработает, поэтому вы можете добавить правило длины:
*
: совпадение любое количество раз
+
: Минимум совпадение 1 раз
?
: совпадение 1 или 0 раз
{m}
: совпадение m раз
{m,}
: минимальное совпадение m раз
{m,n}
: Минимум совпадений m раз, максимум совпадений n раз, m должно быть меньше или равно n
По умолчанию используется жадное сопоставление, то есть те, которые соответствуют условиям, всегда будут совпадать.Если вы хотите предотвратить жадное сопоставление, вы можете добавить правило длины после правила.?
,Например:
/\d{2,}/.exec("1234567890")
//得到匹配结果如下,会匹配到所有数字:
["1234567890", index: 0, input: "1234567890", groups: undefined]
//1、添加?,阻止非贪婪匹配后
/\d{2,}?/.exec("1234567890")
//2、得到匹配结果如下,只会匹配2个数字:
["12", index: 0, input: "1234567890", groups: undefined]
① Используйте группировку
Что если мы хотим сопоставить слово много раз, например regregregregregreg, мы видим, что reg встречается 6 раз подряд.Если мы тупо пишем 6 регов в регулярном выражении, это точно не подходит, мы можем использовать группировку для достижения , помещаем рег внутрь скобок, а затем повторяем группировку 6 раз,/(reg){6}/
:
/(reg){6}/.test("regregregregregreg") //匹配成功,返回true
Однако для использования группировки таким образом необходимо предварительное условие, т. е. знание того, что совпадающая строка является reg, а затем повторение группировки. Что делать, если вы хотите сопоставить последовательные перекрывающиеся типы, такие как 8899 или 5522, но вы не уверены, что это такое? Тогда мы можем поместить перекрытие сначала в группу, а потом передать\n
(n представляет количество групп) Захватите содержимое этой группы, чтобы оно соответствовало следующему:
/(\d)\1(\d)\2/.exec("2345566789")
//得到匹配结果如下,返回了5566,分组对应的5、6也被返回
["5566", "5", "6", index: 3, input: "2345566789", groups: undefined]
② Захват пакетов
Группировка по умолчанию может быть захвачена, указанная выше\1
,\2
это группировка, захваченная внутри регулярного выражения. Если вы хотите получить внешние данные о сопоставлении групп, вы можете использоватьRegExp.$1-$9
чтобы получить. Пока регулярное выражение совпадает, оно будет. можно использоватьtest
,exec
или ул.replace
способ получить$1-$9
.
Используйте тест:
/([a-z]{2})(\d{2})/.test("xyz123")
RegExp.$1 //返回第一个分组表达式匹配到的内容 yz
RegExp.$2 //返回第二个分组表达式匹配到的内容 12
Используйте замену:
"xyz123".replace(/([a-z]{2})(\d{2})/,'$2$1')
//会返回结果:x12yz3,就是把第一个分组匹配到的内容yz和第二个分组匹配到的内容12互换了
③ Пакет не захвачен
Если вы не хотите захватывать группу, просто добавьте ее в группу?:
просто хорошо
/([a-z]{2})(?:\d{2})/.test("xyz123")
RegExp.$1 //返回第一个分组表达式匹配到的内容 yz
RegExp.$2 //分组未被捕获 返回空字符串
3. Резюме
В этой статье мы не будем вдаваться в подробности о значении метасимволов и о том, как использовать их в комбинации, это вещи, которые нужно запомнить. Вместо этого я научу вас думать о том, как разбивать регулярные выражения, как шаг за шагом анализировать требования, которые должны быть сопоставлены, и разбивать длинные и сложные требования на короткие и простые. на три вопроса души:соответствовать чему? Матч не какой? Сколько раз совпадает?для завершения регулярного выражения, которое соответствует требованиям.
Наконец, я рекомендую вам веб-сайт, который иллюстрирует регулярные шаблоны:regexper.com