Регулярные выражения

Russian main discussion
  • Author
  • Message
Offline
Posts: 1161
Joined: Sun Oct 20, 2013 11:44 am

Post by Skif_off »

Изменено: квантификаторы регулярных выражений теперь обладают классической жадностью. Чтобы сделать их сверхжадными (старый принцип), используется "+" после квантификатора, например, "\d*+".
4.9.1 dev, есть файл, по структуре как обычный ini Параметр=Значение, нужно убрать все значения, пишу

Code: Select all

что: ^([^=]+=).*$
чем: \1
В 4.8.5 работало номально, сейчас захватывается всё. Но звездочка должны быть в любом случае - не все параметры со значением. Сработало только так
^([^=]+=).*?$
Почему, если по умолчанию не жадные?

И еще не понял по началу и концу строки:

Code: Select all

^.*$
должно быть равно

Code: Select all

^[^\r\n]*$
или нет? В 4.8.5 оба выражения работают одинаково.

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Skif_off wrote:
Изменено: квантификаторы регулярных выражений теперь обладают классической жадностью. Чтобы сделать их сверхжадными (старый принцип), используется "+" после квантификатора, например, "\d*+".
4.9.1 dev, есть файл, по структуре как обычный ini Параметр=Значение, нужно убрать все значения, пишу

Code: Select all

что: ^([^=]+=).*$
чем: \1
В 4.8.5 работало номально, сейчас захватывается всё. Но звездочка должны быть в любом случае - не все параметры со значением. Сработало только так
^([^=]+=).*?$
Почему, если по умолчанию не жадные?
Просто Вы где-то запутались.
Прочитайте внимательно цитату, которую Вы привели, ну или AkelHelp-Rus.htm
".*" - обладает классической жадностью, т.е. этот шаблон просто обязан захватить максимальный вариант текста, с перебором из возможных (весь текст до конца), а ".*?" - ленивый шаблон, который захватит минимальный вариант, с перебором из возможных (одна строка).
Для описанного случая, лучше использовать такой шаблон:

Code: Select all

^([^\n\r=]++=)[^\n\r]*+$
-при использовании на больших файлах не будет тормозить, т.к. время затрачиваемое кодом движка регэкспов на проверку шаблона, будет минимальным.
Skif_off wrote: И еще не понял по началу и концу строки:

Code: Select all

^.*$
должно быть равно

Code: Select all

^[^\r\n]*$
или нет? В 4.8.5 оба выражения работают одинаково.
Нет, это не равнозначные шаблоны.
1. Совпадает если:
а) Сразу за началом строки следует любой символ ноль или более раз;
б) следует символ конца строки.
Причем будет выбран максимально возможный вариант, т.е. весь текст до самого последнего символа конца строки.

2. Совпадает если:
а) Сразу за началом строки следует любой символ, кроме перевода строки и перевода каретки, ноль или более раз.
б) следует символ конца строки
Даже при условии жадности квантификатора "*", захвачена будет всего одна строка, т.к. из захватываемого диапазона исключены перевод строки и перевод каретки.
Last edited by YuS on Thu Sep 18, 2014 2:12 pm, edited 2 times in total.

Offline
Posts: 582
Joined: Mon Apr 08, 2013 9:50 pm
Location: Win7SP1x64, APx64

Post by Drugmix »

Instructor
да, не падает вроде.

Offline
Posts: 1161
Joined: Sun Oct 20, 2013 11:44 am

Post by Skif_off »

YuS wrote:Нет, это не равнозначные шаблоны.
В 4.8.5 они работали совершенно одинаково и как-то было очевидно для меня - привык думать, что точка исключает переводы строк. Теперь нет, надо было изучать регэкспы до того, как остановился на AkelPad :) Позже просто уточнил бы нюансы оного.
Такой вопрос: по реализации какие отличия от канонiчных PCRE, по которым, кажется, больше всего инфы?

Что-то начал сомневаться :) Если у кого будет свободное время, взгляните, пожалуйста, BibTeX, Grub4Dos, KiXtart, LaTeX, nnCrob - всё приемлемо?

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Skif_off wrote: В 4.8.5 они работали совершенно одинаково и как-то было очевидно для меня - привык думать, что точка исключает переводы строк. Теперь нет, надо было изучать регэкспы до того, как остановился на AkelPad :) Позже просто уточнил бы нюансы оного.
Так было до версии 4.8.9, включительно. В документации было замечание о том, что ".*" не является жадным шаблоном, т.е. он ленивый и соответственно, выбирался наименьший возможный вариант... но точка = любой символ, поэтому он и не исключает переводы строк...
Добавлено:
Да, забыл упомянуть, что существуют реализации (диалекты) в которых точка - любой символ, кроме перевода строки. В AP есть возможность включить такое поведение с помощью опций (модификаторов): "(?опция)"
Например:

Code: Select all

^(?-s).*$
будет равнозначно такому шаблону:

Code: Select all

^[^\n]*$
но не равнозначно:

Code: Select all

^.*?$
хотя внешне отличий не будет, т.к. захватываться будут только строки.
В общем, решение универсальное, на любой вкус...
Skif_off wrote: Такой вопрос: по реализации какие отличия от канонiчных PCRE, по которым, кажется, больше всего инфы?
Теперь, правила максимально приближены, но это нигде не заявлялось и не документировалось, так что требовать полного совпадения - не стоит, но документацию использовать вполне можно. А вообще, если интересуют регулярки, то за основу изучения можно взять книгу "Регулярные выражения" Джеффри Фридл (есть на русском языке), описано достаточно доступно и понятно.
Skif_off wrote: Что-то начал сомневаться :) Если у кого будет свободное время, взгляните, пожалуйста, BibTeX, Grub4Dos, KiXtart, LaTeX, nnCrob - всё приемлемо?
Наверное, в связи с изменением в движке, секции QuotesRE, также потребуют изменений...

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

Регулярка для регулярных выражений JScript
Пытался решить проблему неэкранированных прямых слэшей внутри квадратных скобок. Получил переполнение стэка и перегрев CPU, хорошо, что не у компьютера. Вынужден обратиться за помощью к уважаемому сообществу. Расписал проблему, как мог, подробно:

1. перед «RegExp» МОЖЕТ быть только:
— перевод строки
— открывающие скобки {[(
— знаки ,;:=!?&|

Code: Select all

(?<=[{\[(,;:=!?&|\n])
— произвольное количество пробелов / табуляций

Code: Select all

[\x09\x20]*
2. далее — сама регулярка:
— открывающий прямой слэш (обязательно)

Code: Select all

(/
3. первым символом регулярки НЕ МОЖЕТ быть:
— прямой слэш (иначе это комментарий) /
— закрывающая круглая скобка )
— квантификаторы *?+

Code: Select all

[^/)*?+]
(без квантификатора — хотя бы один символ в выражении должен быть)
правило удалено - с ним мороки ещё больше, а ведь нужно: без него с комментариями (//) до и после не разобраться...

4. следующее условие (возможно):
— минимальное (до следующего условия) количество любых символов

Code: Select all

(.*?
— любые символы (не менее 1) между парой неэкранированных
(четное количество обратных слэшей) квадратных скобок
призвольное количество раз

Code: Select all

(?<=[^\\])(\\\\)*\[.+?(?<=[^\\])(\\\\)*\])*
5. после этого:
— минимальное (до следующего условия) количество любых символов

Code: Select all

.*?
6. закрывающий неэкранированный (четное количество обратных слэшей) прямой слэш (обязательно)

Code: Select all

(?<=[^\\])(\\\\)*/)
7. после «RegExp» МОЖЕТ быть:
— модификаторы (возможно) (не подсвечиваем)

Code: Select all

[gim]{0,3}
— произвольное количество пробелов / табуляций

Code: Select all

[\x09\x20]*
8. далее:
— закрывающие скобки }])
— знаки ,;:.
— перевод строки

Code: Select all

(?=[}\]),;:.\n])
получаем:

Code: Select all

`(?<=[{\[(,;:=!?&|\n])[\x09\x20]*(/(.*?(?<=[^\\])(\\\\)*\[.+?(?<=[^\\])(\\\\)*\])*.*?(?<=[^\\])(\\\\)*/)[gim]{0,3}[\x09\x20]*(?=[}\]),;:.\n])`
Last edited by Serge Yolkin on Tue Sep 23, 2014 8:41 pm, edited 4 times in total.

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

Да, примеры "проблемных" строк:

Code: Select all

var r = /.*[/\*]/img;
начало захваченной подстроки - неэкранированный слэш внутри квадратных скобок, то, что перед ним (после знака "равно") - не захватывается;

Code: Select all

var r = /.*[\/\*]/img;	// комментарий
не определяется, как регулярное выражение - символ комментария мешает (прямые слэши), а должно всё закончится на ближайшем неэкранированном прямом слэше - перед IMG.

PS: до правки эти два поста содержали откровенный косяк, если кто успел их прочитать - прошу прощения (я ведь продолжаю решать эту задачку)

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Serge Yolkin wrote:Да, примеры "проблемных" строк
Пара наводящих вопросов:
1. Зачем в определяемой части регэкспа выделять шаблон в квадратных скобках? (регэксп может быть и без квадартных скобок)
2. Шаблон будет использоваться в кодере или как-то ещё?

Ну и примеров бы побольше с регэкспами, желательно нестандартных, но синтаксически верных для java, чтобы можно было потестировать...

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

YuS
1. В квдратных скобках допускается неэкранированный прямой слэш, который моя текущая (рабочая) регулярка считает концом регэкспа
без квадратных скобок может - поэтому *
2. Да, только в кодере

Примеры приведу сегодня вечером, на работе проблематично :)

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Serge Yolkin wrote:YuS
1. В квдратных скобках допускается неэкранированный прямой слэш, который моя текущая (рабочая) регулярка считает концом регэкспа
без квадратных скобок может - поэтому *
2. Да, только в кодере
На уровне плясок с бубном и прочего шаманства, с учетом того, что внутри всего один слеш (для учета более одного слеша, необходимы ещё пляски):

Code: Select all

(?<=[{\[(,;:=!?&|\n])[\x09\x20]*(/[^/]*/?[^/]+/(?!/))[gim]{0,3}[\x09\x20]*(?=[}\]),;:.\n])
PS
А вообще, в процессе тех самых плясок, сложилось впечатление, что движок сильно не любит работать со слешами, иногда до степени падения AP. Например, такая регулярка стабильно заваливает AP (x64):

Code: Select all

(?<=[{\[(,;:=!?&|])[\x09\x20]*(/(?:[^/]*/?)*[^/]+/(?!/))[gim]{0,3}[\x09\x20]*(?=[}\]),;:.])
хоть и нет в ней ничего невалидного...

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

YuS
Не, экранированных слэшей - прямых и обратных - может быть сколько угодно, поэтому логика такая:
- находим начало регулярки (условия 1,2)
- ищем неэкранированный (без предстоящего обратного, или с четным числом обратных=экранированные обратные) прямой слэш - конец регулярки (условие 6 с допусловиями 7,8) НО(!)
- если встречаем пару (откр./закр.) неэкранированных квадратных скобок, то всё, что внутри них пропускаем, чтобы не париться (иначе прийдётся парсить весь синтаксис регулярных выражений с вариациями). Экранированные квадратные скобки могут встречаться и снаружи, и внутри неэкранированных.
Вот некоторые примеры (все возможные варианты перебрать невозможно):

Code: Select all

var p=13,r,s='a*b4',t=false;

// Regular expressions
 r = /([\\/])?([^\\/]*)$/;
 r = /([\\/])?([^\\:/]*)$/;	// коммент
  /abc\[def[^\s[\]/]ghi/g.test(s);// здесь одна пара квадратных скобок!
r = /\//i;
 r = /[/\*]/img;		// коммент
 r = /[a-z]{5}/;
 r = /[a-z]{1,5}/;
 r = /([a-z])+/;
 r = /([a-z]{1,5})+/;
r = /f([a-z])/;
r = /f([a-z]+)*/;
r = /a(b)c(d)/;
r = /a(b)?c(d)+?/;
r =(t|/\*/.test(s));
 r =(t|/\*/);			// коммент
r =/./.test(s) && f();
r=/[a-z]/.test(s) && f();
var a = [/a/, /b/];
  a=[/a/,/b/];
var o = { r: /./, x: 2 };	// коммент
  o={r:/./,x:2};
var x = a && /b/.test(s);
 x = a ? /b/ : /c/;// коммент
 x=a?/b/:/c/;
 x=a?/b\\/:/c\/\\/;		// коммент
 x=a?/b\\/:/c\/\\/;		// коммент
 x = !/a/.test(s);
 x = f(/./i);
 x=1*s.replace(/^[^\d]*(\d+).*$/,'$1')/2;
 /\s\n\s+\/\/\\\\/.test(s)?f(null):f(/\\/);
 a=s.search(/\s\n\s+\/f\//gi);
 r=/>\.jjj\n<\s\</
  .exec(s);
 r=/ \n \s/g,
 t=/'/g
 ;
 
// Not a regular expressions
var n = 1/2;// коммент
 n = 1/2/3;
 n = 1/2/p;
 n = 1/(2/p);		// коммент
 n = 1/this.n/3;
 n = 1/this.f(5+4)/3;
 n = 1/this.f(2/3);
 n = 1/2 + (function() { return 3/4; })();
 n = 1/2*(this.x/3 + 2);
 n = 1/2*(this.x + 2/3);
 n =p/2,t=3/p;
 n = f(1/2) + f(3/2);

function f(e){}
первая и последняя строчки добавлены для валидности файла - если сохранить всё это как .js - то можно даже запустить. Сообщений об ошибках не будет. (разумеется, ничего и не произойдёт)

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Serge Yolkin wrote:YuS
Не, экранированных слэшей - прямых и обратных - может быть сколько угодно, поэтому логика такая:
- находим начало регулярки (условия 1,2)
- ищем неэкранированный (без предстоящего обратного, или с четным числом обратных=экранированные обратные) прямой слэш - конец регулярки (условие 6 с допусловиями 7,8) НО(!)
- если встречаем пару (откр./закр.) неэкранированных квадратных скобок, то всё, что внутри них пропускаем, чтобы не париться (иначе прийдётся парсить весь синтаксис регулярных выражений с вариациями). Экранированные квадратные скобки могут встречаться и снаружи, и внутри неэкранированных.
Вот некоторые примеры (все возможные варианты перебрать невозможно):
Чтобы переполнение стека не случилось и у меня, для начала так:

Code: Select all

(?<=[:=!?&;|{\[(\n])[\x09\x20]*(/(?:[^\n\[\\]*+(\\\\)*+(\\\[)?+(?>\[|\\)?(?(3)[^\n\[\\]*+|[^\n\]]+\]))*+[^\n]*(?<![^\\]/)/(?![^gim}\]),;:.\n ]))[gim]{0,3}[\x09\x20]*+(?![^}\]),;:.\n])
Правда, есть пара тонких моментов:
1. В кодере почему-то не срабатывает шаблон на тексте в этой части:

Code: Select all

(?<=[:=!?&;|{\[(\n])[\x09\x20]*
если отсутствуют пробельные символы [\x09\x20]*
Почему так - не знаю, но в самом редакторе по Ctrl+F все находится, т.е. движок отрабатывает правильно.
2. Без расширения условий/ограничений, определить наличие двух и более раздельных регэкспов в одной строке, имхо, невозможно. Сейчас они будут захватываться все-в-одном, т.е. по сути будет один регэксп, заватывается текст от начального слеша до конечного...

PS Да, в кодере из шаблона можно поисключать "\n", т.к. обработка, всё равно идет построчно.

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

YuS
Во! Шаг вперёд. У меня первый тонкий момент не наблюдается ни если регулярка от начала строки, ни при отсутствии пробелов между допустимым символом и началом регулярки. (?)
Кстати, заметил, что при многократном изменении и применении кодер файла Akel надо периодически закрывать, а то подвирать начинает. Воспроизвести проблематично, поскольку обновлений свойств кодера должно быть много, а на чём именно ломается - не зафиксировал. Перезапускаю после 5-10 изменений. (кэш отключен)

Instructor
Если располагаете временем, не прокомментируете проблему? Вроде, алгоритм не очень сложный, а реализовать не получается...

Offline
Posts: 294
Joined: Tue Jul 27, 2010 11:18 pm

Post by Serge Yolkin »

YuS wrote:не любит работать со слешами, иногда до степени падения AP
похоже, дело не в слэшах - что-то с (?:...)

Code: Select all

^\s*?(?:[^;])(\s*\S+)+
тоже завешивает насмерть...

YuS
Offline
Posts: 512
Joined: Sun Sep 15, 2013 8:25 am
Location: 013 в Тентуре, семь по Спирали, налево от Большой Медведицы

Post by YuS »

Serge Yolkin wrote:YuS
Во! Шаг вперёд. У меня первый тонкий момент не наблюдается ни если регулярка от начала строки, ни при отсутствии пробелов между допустимым символом и началом регулярки. (?)
Причина нашлась быстро. Вот эта строка из секции Quotes:

Code: Select all

5	0	${AREA}	0	"/"	"/"	""	""	""
дает такой эффект, т.к. имеет больший приоритет.
Serge Yolkin wrote:
YuS wrote:не любит работать со слешами, иногда до степени падения AP
похоже, дело не в слэшах - что-то с (?:...)

Code: Select all

^\s*?(?:[^;])(\s*\S+)+
тоже завешивает насмерть...
В моем регэкспе "?:" тоже присутствует и он работает, да и не только в нем, тут видимо какое-то определенное сочетание символов и квантификаторов, не обязательно рядом стоящих, вызывает падение...
Post Reply