Как работают такие регулярные выражения?
Я не могу разобраться, как работает это регулярное выражение в Lex:
1) \"([^\\\"]|\\\n|\\.)*\"
Первое выражение отлавливает записи такого рода : "one" или "test". То есть слова в двойных кавычках.
Мне известно об этом первом регулярном выражении следующее:
\" - экранирование спец. символа кавычка
(что-то в скобках)* - звёздочка означает любое (в том числе и 0) число вхождений символа
Затем внутри скобок стоят | , что означает или, то есть выбирается [^\\\"] или \\\n или \\.
Пытаюсь подробнее разобрать, что эти [^\\\"] и \\\n и \\. означают.
Начну с [^\\\"]. Циркумфлекс(^) в квадратных скобках означает выбрать любую цепочку символов, если символы не равны \ или " (вижу экранирование слэша и экранирование кавычки).
Затем за символом или идёт \\\n. Тут я опять вижу эранирование символа слэш и переход на новую строку.
А потом - \\. Экранируют точку(по определению просто точка принимает любой символ, кроме \n). То есть шаблон хочет найти символы \.
Вопрос: как всё вышесказанное помогает отлавливать слова типо "one" или "test" ? Верно ли я распознал,что означает каждая из записей?
Конкретно непонятно, зачем нужно \\\n и \\.
Ответы (2 шт):
Это выражение находит три типа строк, заключенных в кавычки:
Первая альтернатива: строки из любых символов внутри которых нет \.
"one"
Вторая альтернатива: добавляют к первым строкам строки, внутри которых есть разрыв в виде новой строки перед которым есть \
"\
"
и
"one\
two"
Третья альтернатива: добавляют к первым строкам строки, в которых есть слеш с любым символом.
"\o" и "one\"two" и "one\\two"
Мне кажется, что здесь есть лишние экранирования перед " (или это особенности lex). По крайне мере их не воспринимает https://regex101.com/, а сам символ " не несет специального значения. В третьей альтернативе экранируется не точка, а слеш.
Если не рассматривать простые случае для 2 и 3, когда они возвращают сами себя, то 2 добавляет разрыв, если перед ним слеш, 3 - это экранирования одного любого символа с помощью слеша и все это внутри строки, которая находит 1.
Для 3 я бы сделал тоже множество например, ["\\]
Да, и для поиска "one", "test" достаточно \"([^\\\"])*\".
Это регулярка для матчинга строк в двойных кавычках, записанных по правилам многих языков программирования, например, Си и Си++, Javascript, JSON, C#, Java (хотя в некоторых из них и нет возможности перенести строку).
var regex = /\"([^\\\"]|\\\n|\\.)*\"/g
function f() {
var someString = "строка \
продолжается \x20 \u0020 \u{20}\
кавычка \" и обратный слеш \\ и перед переносом \\\
а может настоящий перенос?\n\
или экранирование\ невпопад\
ну и пора закруглятьося,\
но сначала - обратный слеш\\"
var s = "пора искать"
}
(""+f).match(regex).map(s => console.log(s))
Как работает?
Что может быть в кавычках? Обычный символ или нечто экранированное обратным слешом. Но сам слеш тоже может быть экранирован другим слешом. Мы не можем просто обрабатывать \\, потому что ситуации \\\" и \\\\" для нас совершенно разные - вторая заканчивает строку, а первая - нет. Значит обрабатывая экранирующий слеш нам надо точно знать, что он именно экранирующий. Так что в первую ветку берём нормальные символы - всё кроме кавычки (она завершает строку) и обратного слеша - он точно что-то экранирует. Теперь для остальных веток нам известно, что они начинаются со слеша (кавычка завершает строку - с ней ничего делать не надо). Значит мы хотим обработать различные версии экранирования. Во-первых, \0, \7, \07, \x20, \u0020, \u{1f60b}, \\, \n, \t и другие, а некоторые языки позволяют влепить экранирование вообще перед любым символом. Во-вторых, непосредственно перенос строки. Теоретически, мы должны были бы перечислить все эти варианты, но если посмотреть на них внимательнее, то становится ясно, что для нас опасен только \\, а остальное может пройти по основной ветке - там не встречается второй слеш. Поэтому мы несколько упрощаем выражение и говорим, что после \ может следовать любой символ (который точно экранируется слэшом), а если слеш экранирует более длинную последовательность, то с этим разберётся основная ветка - для нас это безопасно. Почему надо съесть хотя бы один символ? Чтобы откатываясь назад алгоритм поиска не смог бы разбить \\ на два вхождения \. Ну а почему отдельно вынесен перенос строк - ты сам сказал - он не матчится на точку. Правда, в зависимости от языка, операционной системы и способа получения строки в ней может всплыть перенос строки из \r\n, а не просто \n - не уверен, обрабатывается ли эта ситуация регуляркой -возможно стоит тоже добавить вариант, который может зависеть от матчинга первой ветки на перенос строки, но можно написать более универсальный \\\r?\n. Ну и может захотеться в первую ветку добавить чистый перенос строки, если у нас парсится что-то типа php.
PS: А сами кавычки в регулярке по идее экранирования не требуют. И это явно не регулярка из строки, поскольку в строке потребовалось бы больше экранирований (привет, Джава). Хотя я не понял, где она написана, может там правда так надо.