Посоветуйте тулзу для убиения комментариев в коде

0000

Надо из PL/SQL кода почистить, но может от других языков подойдет...
Вот правила образования
— дальше строка считается комментарием
/* комментарий внутри */
Зачем:
Дали пакет длиной в пару километров из-за того, что старый код не удалялся, а комментился (это нормально, но не в таком масштабе а так же из-за того, что автор либитель писать вот такое

-- Пишем в лог
PKG_UTILS.LOG_WRITE ('Всем копец!');

Хочу почистить код :( Поиск по инету ничего не дал.

freezer

grep?

0000

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

/*
bla-bla
-- bla-bla
/*
bla-bla
*/

freezer

тогда вопрос надо ставить так: помогите написать регулярку для вырезания комментов из PL/SQL
grep под винду не сложно найти

spitfire

Скорее, sed

durka82

Я виндузятник, греюсь в биореакторе. Не уверен, что напишу корректную регулярку, которая вот, например, такие приколы будет обходить
code:
/*
bla-bla
— bla-bla
/*
bla-bla
*/

Мб тогда стоит сначала написать регулярку, которая будет искать такие ошибки?
Я виндузятник, греюсь в биореакторе

Не то, чтобы очень рекомендую, но мб поможет RegexBuddy или Editpad pro (первое скорее для построения и применения регэкспов, а второе - редактор, в котором это не так уж и плохо прикручено).

0000

Блин, неужто так необходимо regexp курить то? :(
Скока всяких тулзов понаписали, а такого нету. Для VB есть, а для PL/SQL не нашел.

durka82

Скока всяких тулзов понаписали, а такого нету. Для VB есть, а для PL/SQL не нашел.

Или ты первый, или плохо искал.
Блин, неужто так необходимо regexp курить то?

А он один раз раскуривается. а потом от него тащишься-тащишься-тащишься-тащишься-тащишься- :smirk:
Пока не наткнешься на задачу, которой он не того :(

kruzer25

А нафига тут регэкспы? Здесь никакие регэкспы, здесь надо тупо идти по строке с одним из трёх состояний - никаких комментариев, комментарий первого типа, комментарий второго типа, и в зависимости от текущего символа (и мб следующего) переходить между состояниями и писать/не писать в выходную строку.
Правда (для какого-нибудь С) будут жестокие проблемы с:

#define COMMENT_START /*
#define COMMENT_END */
COMMENT_START text COMMENT_END

(кстати, а будет ли такой код там корректным?)
Но тут тебе с регулярными выражениями придёт полный пиздец, а с проходчиком по строке - дело просто усложнится, надо будет ещё уметь обрабатывать директивы #define.

Andbar

вообще, тебе нужно два регулярных выражения, по которым будет вырезаться текст, вот вариант (синтаксис PCRE, для grep-а надо будет адаптировать, не уверен, что получится):
#/\*.*?\*/#m
#--.*?$#
(именно в такой последовательности)
Единственный уточняющий момент: /*/ считается валидным комментарием или нет?

kill-still

Словогрыз - регулярки любой сложности.
Может править прямо в буфере.

0000

Насколько я понимаю regexp'ы могут различаться от продукта к продукту, т.е. Unix-овый и виндузятный отличаются, Словогрыз - то же отжельная песня... Вопрос такой - заботав один, трудно ли перейти на другой?
P.S. Слишком редко попадаются задачи, где нужен regexp, потому успеваю забывать что умел.

katrin2201

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

0000

"Это" я так понял для Unix?
Блин, придется regexp покурить :/

salora

Это на перле. Он даже под венду есть.

0000

Блин, вот этого мне тока еще не хватало :(
perl и php мне не катят, поскольку я с ними не знаком, а из-за такой задачки смотреть что там к чему - наф-наф.
P.S. Тока не надо говорить, что я ленивый. Книги по профессии (Oracle/Informatica) регулярно ботаю.

slonishka

там же уже готовое все. можно даже perl -e делать, если склеить в строку.

0000

Мне перл устанавливать надо. Помнится как то хотел поучить SQL. Почитал доки по MySQL, подумал что это супер БД, установил... Потыкался, офигел, удалил. С тех пор такие сомнительные опыты не ставлю. Как вариант пока рассматриваю скачать аналог грепа и взботнуть regexp - по любому именно эта хрень потребуется.

freezer

да этот перл ставится моментально, потом пользуешься как cscript

slonishka

у вендузятнегов определенно альтернативное сознание. они могут программировать без grep! ;]

katrin2201

если б ты начал действовать, ты бы уже давно получил результат
это не та задача, где надо 10 дней думать, как сделать лучше
а вообще, ты со своей "ленью" перебарщиваешь имхо
свой кругозор надо расширять

0000

Ну как бы большого кодинга у меня нет. То что в этом случае, так это чел такой попался... Обычно размер пакета не превосходит 1 000 строк - в данном случае их 10 000, и более 90% из них камменты (руки оторвал бы за такое, была бы моя воля :mad:)

katrin2201

более 90% из них камменты (руки оторвал бы за такое, была бы моя воля )
а я б наоборот памятник поставил, если комментарии по делу
чем они тебе вообще не угодили, что ты их так упорно хочешь порезать?

0000

Блин, я за все время пытался учить всякого г столько, что самому уже тошно, поскольку оно нафиг никому не надо: WinAPI, Delphi, BDE API, OpenGL, COM, VBA, WSH, C++ (под Win/WinCE lua + что то там еще. Может кому то и покажется это маленьким списком, но я ни разу не был прогером (Oracle - там PL/SQL - это скорее скриптовый язык).

0000

Большая часть камментов это просто старый код. Оставшаяся большая часть - это либо совсем бестолковые, либо могут быть устранены разумным названием переменных, а не i, j, AllDate.

katrin2201

попробуй восприятие изменить
например, переться от каждой новой изученной фенечки

slonishka

имхо это довольно сложно, особенно если речь идет о каком-нибудь COM.

katrin2201

есть такое
но шо ж делать, иногда приходится =)

0000

Чем больше фенечек знаешь, тем больше хочется их копать дальше. Я не резиновый, мне и текущих за глаза.
Да и что то не вижу я света в конце тунеля "прогерство", бесполезный навык по зп обычно :(

katrin2201

ты если не секрет чем занимаешься то?
а то как то это для меня непонятно
комментарии из кода вырезать, винапи, тратата, и не прогер 0.о
ps
Я не резиновый, мне и текущих за глаза.
старость не в радость что ли? =) а что будет через 5 лет? через 10? =)

0000

ты если не секрет чем занимаешься то?
Ну написал же выше - Oracle (SQL, PL/SQL Informatica (Хранилища данных вообщем).
Про код, написал выше, что это не обычный пакет, написанный необычным челом.
а что будет через 5 лет? через 10? =)
Надеюсь по работе больше прогать не придется. Большая часть перечисленных левых скилов, относятся к моему текущему хобби (писанине игрухи на КПК).

slonishka

Надеюсь по работе больше прогать не придется. Большая часть перечисленных левых скилов, относятся к моему текущему хобби (писанине игрухи на КПК).
портируй сразу под Android, чтоб перестраховаться.

0000

Это новая платформа что ли? Че та с развитием мелких компов с обычным, не ARM/MIPS, процами и обычной ОС (WinXP для меня сомнительно будущее мобильных платформ.

slonishka

Че та с развитием мелких компов с обычным, не ARM/MIPS, процами и обычной ОС (WinXP для меня сомнительно будущее мобильных платформ.
это верно, только звонить с помощью таблеток пока не удобно, а остальное — еще слишком далекое будущее.
про обычную ОС — лол. =)

0000

Ну Linux на любых устройствах уже конечно более привычен (эт для меня WinXP пока пуп Земли). Т.е. что то мне кажется будет битва *Nix vs Win на этих платформах, а всякие обрезки типа Symbian и WinCE пойдут лесом вместе с Android.
2Муртаза, включи прием личных сообщений, да? :grin:

slonishka

Android — это линукс.

0000

Мля :( Начать что ли Linux смотреть... Неее! Бум считать, что я этого не видел :grin:

slonishka

будем считать, что ты и этого не видел: http://www.openhandsetalliance.com/oha_members.html

0000

:mad: :mad: :mad:

smit1

>имхо это довольно сложно, особенно если речь идет о каком-нибудь COM.
Угу, у некоторых отцов COM так и не получилось осилить :petuh:

slonishka

да, пианист иногда это вспоминает с ужасом. =)

pitrik2

народ
вы с ума сошли?
какая нах регулярка?
что она будет делать в таких случаях

select 1 "/* lala */" from dual


select 1
-- /*
from /*
-- comment */
dual

а?

dgaf

тогда только родной парсер.
вот тут бы как раз мускуль порулил со своими исходниками.

bleyman

А нафига тут регэкспы? Здесь никакие регэкспы, здесь надо тупо идти по строке с одним из трёх состояний - никаких комментариев, комментарий первого типа, комментарий второго типа, и в зависимости от текущего символа (и мб следующего) переходить между состояниями и писать/не писать в выходную строку.
Ты идиот, клинический, теперь я в этом убедился. То, что ты написал, называется "конечный автомат", регекспы являются наиболее удобным языком описания конечных автоматов для работы с текстом.
И языка С ты нифига не знаешь конечно же, но проблема даже не в этом, а в том, что практически у любого языка (и С, как и sql, входит в их число) лексер, бьющий поток на лексемы и выдирающий комменты, написан на регексах же. Директивы обрабатываются после того, как комменты вырезаны.

bleyman

>> select 1 "/* lala */" from dual
Значит, ей придётся ещё и строчки обрабатывать.
Со вторым примером нет ни малейшей проблемы.

Dasar

То, что ты написал, называется "конечный автомат", регекспы являются наиболее удобным языком описания конечных автоматов для работы с текстом.
regex не является полноценным языком описания конечных автоматов.

vall

а если там может быти типа такого? (SQL я не знаю, если чо)
'"' bla "/*" bla '+' bla '*/' bla "\"" ?
имхо тут какая-то рекурсивная регулярка нужна, если обычной и хватит то выглядеть она бедет ниибически.

9173306234

пытался учить всякого г столько, что самому уже тошно, поскольку оно нафиг никому не надо
+1

kruzer25

вообще, тебе нужно два регулярных выражения, по которым будет вырезаться текст, вот вариант (синтаксис PCRE, для grep-а надо будет адаптировать, не уверен, что получится):
#/\*.*?\*/#m
#--.*?$#
(именно в такой последовательности)
И что будет на такой тривиальный случай, как
--/*
doSomething;
--*/
?

kruzer25

Ты идиот, клинический, теперь я в этом убедился. То, что ты написал, называется "конечный автомат"
Теперь модно считать клиническими идиотами тех, кто может додуматься до/знает какое-то понятие, но не знает его общепринятого обозначения?
регекспы являются наиболее удобным языком описания конечных автоматов для работы с текстом.
Во-первых, они необязательно будут наиболее удобным языком в каком-то конкретном случае.
Во-вторых, в общем случае то, что я описал, не может быть выражено регэкспами. В каких-то частных случаях - да, но не в общем.
практически у любого языка (и С, как и sql, входит в их число) лексер, бьющий поток на лексемы и выдирающий комменты, написан на регексах же.
Да ну?

pitrik2

практически у любого языка (и С, как и sql, входит в их число) лексер, бьющий поток на лексемы и выдирающий комменты, написан на регексах же.
ага, тож не понял что он хотел сказать

kruzer25

Ну почему же? Что он хотел сказать - понятно (если я правильно понял, в PHP это называется tokenizer).
Но в том, что это делается на регэкспах - ну просто дикие сомнения. Не делают такие вещи на регэкспах. Зачем делать то, что можно написать несколькими строчками дополнительного кода в проходчике строки, десятиэтажными регулярками, в которых никто не разберётся, которые будут мешать друг другу, у которых будут всякие побочные эффекты, и которые не всегда вообще можно написать?

pitrik2

Что он хотел сказать - понятно (если я правильно понял, в PHP это называется tokenizer)
т.е. в пхп tokenizer "выдирает комментарии"?
я всегда думал что он только разбивает строчку, а о такой сущности как коммент ваще не знает

kruzer25

Я сейчас точно не скажу, но, по-моему, он как раз бьёт строчку на что-то вроде
открывающий_тэг строка открывающая_скобка строка_в_кавычках закрывающая_скобка коммент_до_конца_строки многострочный_коммент закрывающий_тэг.

tokuchu

ага, тож не понял что он хотел сказать
В теории компиляторов, текст изначально бъётся на лексемы. Соответственно есть проги, генерящие лексические анализаторы (flex, например). На вход получают файл с набором регулярных выражений, соответствующих лексемам.

Andbar

А ты заранее проверь наличие подобной фигни. Задачка то разовая, придумывать ради неё универсальное средство - время зря терять.

pitrik2

вот мне тож показалось что он компиляторы имел ввиду, а не токенайзеры
ну дык разве регвыражения существовали когда создавался Си?
потом я как-то использовал чтото такое, вроде lcc
дык там регулярками и не пахло

kruzer25

Именно для такой задачи гораздо легче написать нормальный обработчик, а не трахаться с регэкспами.

kruzer25

<?php
class CommentDescription {
public $sOpening;
public $sEnding;
public $sReplaceWith;
public function __construct($sOpening, $sEnding, $sReplaceWith) {
$this->sOpening = $sOpening;
$this->sEnding = $sEnding;
$this->sReplaceWith = $sReplaceWith;
}
}

function stripComments($sCodeWithComments) {

$sCode = '';
$arrComments = array(
new CommentDescription('/*','*/',''
new CommentDescription('--',chr(0x0dchr(0x0d
new CommentDescription('--',chr(0x0achr(0x0a
);

$bInComment = false;
$iCommentType = null;

$l = strlen($sCodeWithComments);
for($i=0;$i<$l;$i++) {
if($bInComment) {
if(substr($sCodeWithComments,$i,strlen($arrComments[$iCommentType]->sEnding == $arrComments[$iCommentType]->sEnding) {
$bInComment = false;
$i += strlen($arrComments[$iCommentType]->sEnding) - 1;
$sCode .= $arrComments[$iCommentType]->sReplaceWith;
continue;
} else {
continue;
}
} else {
foreach($arrComments as $key => $oComment) {
if(substr($sCodeWithComments,$i,strlen($arrComments[$key]->sOpening == $arrComments[$key]->sOpening) {
$bInComment = true;
$iCommentType = $key;
break;
}
if($bInComment) {
$i += strlen($arrComments[$iCommentType]->sOpening) - 1;
continue;
} else {
$sCode .= substr($sCodeWithComments,$i,1);
}
}
}
}
return $sCode
}
?>

Сколько там ушло, 12 минут?
ЗЫ: Не тестил, возможны мелкие баги.

ark21

cat 1.qq | perl -ne 'print unless m/^--/' | perl -e 'while (<>) {$line .= $_;}; $line =~ s/\/\*.*?\*\///sg; print $line;'
минуты 2.
всякие йобнутые случаи не находит (один хрен их не будет с вероятностью 95%) но для одноразового скрипта идеальный вариант, если возникают проблемы модифицируется еще за минуту

tokuchu

вот мне тож показалось что он компиляторы имел ввиду, а не токенайзеры
ну дык разве регвыражения существовали когда создавался Си?
Ну может не в форме perlre, но наверняка теория уже была. Взять ту же форму Бэкуса-Наура.

katrin2201

не думаю, что в стандарте Си где то регламентируется имплементация, а компиляторы разрабатываются/модифицируются до сих пор.
я к тому, что какая разница, были ли регэкспы когда придумывался си?

kruzer25

perl -ne 'print unless m/^--/' | perl -e 'while (<>) {$line .= $_;}; $line =~ s/\/\*.*?\*\///sg; print $line;'
Говно какое-то, честное слово.
Да ещё и нерасширяемое нихуя; оно не только с вложенными комментами работать никогда не сможет, но и с
insert into `table` values('/*stringtoinsert*/');

karkar

Если еще актуально, вот мой вариант:
http://stuff.thedeemon.com/nocom.exe (119 КБ)
Читает из стандартного ввода, выводит на стандартный вывод, т.е. запускать
nocom.exe <infile.sql >outfile.sql
Знает два вида комментариев, три вида строк (в одинарных, двойных и обратных кавычках знает, что внутри строки две кавычки подряд не заканчивают строку. Соответственно, комментарии внутри строк не вырезаются.
На тестовом примере
simple text: a1a aa1a
single line comment: aa2a --bbb
other comment: aa3a /* bbb*/ aa3a
multiline comment: aa4a /*bbbb
bbbb
bbbb */ aa4a
single in multi: a5aa /* bbb--ccc */ aa5a
simple string: a6aa 'dddd' aaa6
simple string with one apostr.: aaa7 'dd''dd' aaa7
comments in string: aaa8 'd/*ee*/d --ff''f' aaa8
comments in string: aaa9 "d/*ee*/d --ff""f" aaa9
comments in string: aaa10 `d/*ee*/d --ff``f` aaa10
comments around strings: aaa14 /* 'd/*ee*/d --fff' "ddd" `ddd` */ aaa14
strings in single line comments: aaa15-- "d/*ee*/d --fff" 'ddd' `ddd` bbb
nested strings: "aaa16 /*zz*/ 'bbb `dd /*zz*/ dd` /*zz*/ bb -- bb'aaa" /*bbb*/ aa16

Выводится:
simple text: a1a aa1a
single line comment: aa2a
other comment: aa3a aa3a
multiline comment: aa4a aa4a
single in multi: a5aa aa5a
simple string: a6aa 'dddd' aaa6
simple string with one apostr.: aaa7 'dd''dd' aaa7
comments in string: aaa8 'd/*ee*/d --ff''f' aaa8
comments in string: aaa9 "d/*ee*/d --ff""f" aaa9
comments in string: aaa10 `d/*ee*/d --ff``f` aaa10
comments around strings: aaa14 aaa14
strings in single line comments: aaa15
nested strings: "aaa16 /*zz*/ 'bbb `dd /*zz*/ dd` /*zz*/ bb -- bb'aaa" aa16

Escape-последовательности не реализовывал, на них гипотетически могут быть глюки.
Исходник в 20 строк на Окамле:
type t = Out | OneLine | MultiLine | Quote of t * char | Q1 of t * char;;
let isquote c = (c='\'') || (c='"') || (c='`');;
let rec filter state =
try
let c = input_char stdin in
let newstate, out = match state, c with
| Out, '-' -> let c2 = input_char stdin in if c2 = '-' then OneLine, false
else (print_char c; print_char c2; Out, false)
| Out, '/' -> let c2 = input_char stdin in if c2 = '*' then MultiLine, false
else (print_char c; print_char c2; Out, false)
| Out, _ -> (if isquote c then Quote(Out, c) else Out true
| OneLine, '\n' -> Out, true
| OneLine, _ -> OneLine, false
| MultiLine, '*' -> let c2 = input_char stdin in if c2 = '/' then Out, false else MultiLine, true
| MultiLine, _ -> (if isquote c then Quote(MultiLine, c) else MultiLine false
| Quote(st, ch _ -> (if ch=c then Q1(st, c) else Quote(st, ch (st = Out)
| Q1(st, ch _ -> (if ch=c then Quote(st, c) else st (st = Out)
in (if out then print_char c; filter newstate)
with End_of_file ->
in filter Out;;

Простой конечный автомат. У кого есть желание записать его в виде регэкспа? ;)

katrin2201

чувак перловский интерпретатор боится ставить, а ты окамл =)

karkar

Я дал ссылку на exe, там вообще ничего ставить не надо - запустил и пользуйся.

Marinavo_0507

рекурсия не хвостовая кажись

katrin2201

ч0рт, зачот =)

0000

Псиб, после праздников погоняю :)

karkar

Вполне себе хвостовая, имхо.
Можно проверить на длинном файле. Если вдруг не хвостовая, будет переполнение стека..

karkar

Да, ты был прав, из-за внешнего try/with была не хвостовая.
Теперь исправил, заодно убрал лишнее состояние и сократил до 17 строк:
type t = Out | OneLine | MultiLine | Quote of t * char;;
let isquote c = (c='\'') || (c='"') || (c='`');;
let rec filter state =
let c = input_char stdin in
let newstate, out = match state, c with
| Out, '-' -> let c2 = input_char stdin in if c2 = '-' then OneLine, false
else (print_char c; print_char c2; Out, false)
| Out, '/' -> let c2 = input_char stdin in if c2 = '*' then MultiLine, false
else (print_char c; print_char c2; Out, false)
| Out, _ -> (if isquote c then Quote(Out, c) else Out true
| OneLine, '\n' -> Out, true
| OneLine, _ -> OneLine, false
| MultiLine, '*' -> let c2 = input_char stdin in if c2 = '/' then Out, false else MultiLine, true
| MultiLine, _ -> (if isquote c then Quote(MultiLine, c) else MultiLine false
| Quote(st, ch _ -> (if ch=c then st else Quote(st, ch (st = Out)
in (if out then print_char c; filter newstate)
in try filter Out with End_of_file -> ;;

Теперь точно хвостовая, 15-меговый файл съедает легко. Ехе-шник обновил.

bleyman

> regex не является полноценным языком описания конечных автоматов.
Поясни мысль, пожалуйста. Я, видишь ли, могу по произвольному регексу построить автомат и наоборот, по произвольному автомату построть регекс, поэтому меня как-то удивляет такое заявление. Хотя я согласен, что некоторые автоматы описывать регексами будет нелегко, да и практические задачи (типа "убрать все комменты") может оказаться тяжелее перефигачить на понимаемые регексами "принадлежит ли слово языку и если да, то как оно матчится", чем на конечные автоматы.
Вот такая штука:
^(?'capture' "[^"]*") | (?[^\n\r]*
если матчится, то кэпчурит в группу "capture" всё до первого коммента, то есть если сделать Replace("${capture}" то выкусится первый коммент. Соответственно, нужно дописать вокруг немножко кода, который всё заматчит и зареплейсит (а то и подпатчить регекс, чтобы он в эту группу кэпчурил много кэпчуров, которые потом отдельный код сконкатенировал и вернул бы). А ещё это не совсем чистый регекс, потому что писать negative lookahead на чистом регексе я бы умер (хотя, насколько я понимаю, компилится оно всё равно в конечный автомат без наворотов).
Окей, мне тоже код на окамле нравится больше, хоть регекс и короче в двадцать раз =)
2Пенартур: человек, считающий себя программистом и при этом вынужденный придумывать своё определение конечного автомата, является клиническим идиотом.
2алл: регексы вообще-то придумали в пятидесятых годах, затем Кен Томпсон добавлял соответствующий синтаксис в разные редакторы, затем этот кусок из одного из них вытащили и сделали отдельной прогой (которую назвали grep потому что именно такой командой оно запускалось в редакторе затем Томпсон сделал язык B, а затем уже Керниган и Риччи сделали вначале BCPL, а потом и C. God bless Wikipedia!

Dasar

Я, видишь ли, могу по произвольному регексу построить автомат и наоборот, по произвольному автомату построть регекс, поэтому меня как-то удивляет такое заявление
утверждение: по произвольному автомату можно построить regex - неверно.
у автомата есть память - в regex-ах памяти нет.
соответственно: контекстно зависимые или рекурсные вещи на regex-ах хрен сделаешь
ps
также regex-ы неудобны с эксплуатационной точки зрения:
1. нет повторного использования
2. нет разбиения на отдельные части
3. предыдущие пункты + более мелкие - приводят к низкой читабельности regex-ов, что приводит к большому кол-ву ошибок в них

kruzer25

по произвольному автомату построть регекс
Или всё-таки то, о чём я говорил, называется не автоматом, или тебе как минимум придётся пользоваться новомодными рекурсивными регэкспами, которые появились сравнительно недавно.
человек, считающий себя программистом и при этом вынужденный придумывать своё определение конечного автомата, является клиническим идиотом
Ясно, то есть, ты считаешь клиническими идиотами тех, у кого нет каких-то конкретных знаний.
А мне вот кажется, что знания приложаться, и, больше того - по-твоему, клиническими идиотами надо вообще считать всех, кроме ботанов-задротов, да и с ботанами-задротами тоже не всё понятно.

bleyman

DFAs recognize the set of regular languages and no other languages. Тебе алгоритм превращения автомата в регекс процитировать?
Или ты почему-то считаешь, что я под "конечными автоматами" имею в виду конечные автоматы с магазинной памятью, а то и двумя? Нет, я ничего такого не имею в виду!
Да, я согласен, что приведённый окамлокод понятней и удобней для поддержки, чем мой регекс.
2Пенартур: фу, какая предсказуемая предсказуемость тупизны. Нет, ты дебил не потому, что у тебя не хватает знаний, а потому, что ты за все эти долгие годы не удосужился восполнить данный конкретный пробел, например.

Dasar

> Или ты почему-то считаешь, что я под "конечными автоматами" имею в виду конечные автоматы с магазинной памятью, а то и двумя?
встречный вопрос:
почему ты считаешь, что грамматику языка (а в данном треде речь идет именно о возможности описания грамматики языка на regex-ах) можно описать с помощью конечного автомата без памяти?

kruzer25

Нет, ты дебил не потому, что у тебя не хватает знаний, а потому, что ты за все эти долгие годы не удосужился восполнить данный конкретный пробел, например.
И чем же этот конкретный пробел лучше других?
Я вообще-то всю жизнь тем и занимаюсь, что восполняю пробелы. Пробелов - их всегда куча, чем больше их восполняешь, тем больше открывается :smirk:

bleyman

почему ты считаешь, что грамматику языка (а в данном треде речь идет именно о возможности описания грамматики языка на regex-ах) можно описать с помощью конечного автомата без памяти?
---
Наверное, потому, что в данном треде идёт речь о конкретном языке, грамматику которого в данном треде уже два раза описали при помощи конечного автомата без памяти, на окамле и на регексах. Не знаю, как тебе, но мне было с самого начала совершенно очевидно, что это можно сделать.

Dasar

Не знаю, как тебе, но мне было с самого начала совершенно очевидно, что это можно сделать.
также очевидно, что парсер для данной задачи можно написать на ассемблере или на машине тьюринга.
но вот нужно ли?
ps
имхо, парсеры надо писать на что-нибудь типа lexx-а, а не изобретать велосипеды в виде regex-ов или ocaml-а

bleyman

Во-первых, lex, а не lexx (если, конечно, ты не имеешь в виду ограниченно разумный космический корабль со множеством сексуальных расстройств во-вторых, ему на вход подаётся список вида "регулярное выражение" - "код выполняемый в случае успешного матча", так что я не очень понял эту вот ремарку про регекс как изобретение велосипеда =)

kruzer25

ему на вход подаётся список вида "регулярное выражение" - "код выполняемый в случае успешного матча", так что я не очень понял эту вот ремарку про регекс как изобретение велосипеда =)
На основе статьи в википедии, можно составить что-то уродское вроде

\/\*
{
if(!bInComment) {
bInMultilineComment = true;
bInComment = true;
}
}
\*\/
{
if(bInMultilineComment) {
bInMultilineComment = false;
bInComment = false;
} else {
echo '*/';
}
\/\/
{
if(!bInComment) {
bInSinglelineComment = true;
bInComment = true;
}
}
[\n\r]
{
if(bInSinglelineComment) {
bInComment = false;
bInSinglelineComment = true;
}
echo '${0}';
}
{
if(!bInComment) echo '${0}';
}

(если я правильно понял )

Dasar

скорее ему подается набор связанных между собой лексических правил(регулярных выражений)
я не очень понял эту вот ремарку про регекс как изобретение велосипеда =)
соответственно получается, что регекс - это способ описания какого-то маленького кусочка грамматики,
и не надо изобретать велосипед и пытаться описать на regex-е всю грамматику
также одно дело, когда мы явно фиксируем, что:
/* - это есть токен "начало комментария"
и совсем другое дело - когда пишется невообразимая конструкция из слэшей, из который фиг понимается, что хотел сказать автор.
и то, и другое описание - можно считать регулярным выражением, но в одном языке явно фиксируется информация, который хотел высказать автор, а в другом случае - фиксируется какая-то низкоуровневая херотень, которая никакого отношения к мысли автора не имела.
ps
привязка кода - это уже фича, а не основная особенность

Dasar

правильное описание - это что-то типа:

program: (code|comment)*
comment = multi_line_comment | single_line_comment
multi_line_comment = '/*' any_char* '*/'
single_line_comment = '//' symbol* line_break
line_break = '\n' | '\r\n'
code: (token space)*
token: \w+
space: \b+

вот с таким описанием уже можно работать, и вот на такое описание и стоит тратить свое время.
заморочки же с регекспами или с чистым кодом - не стоят потраченного на них время.
ps
в описании есть неточности.

kruzer25

в описании есть неточности.
В описании - критические неточности, вроде того, что оно не знает про то, что бывают строки '/*test*/'. А если их фиксить, если у тебя в code будут допустимы все эти символы - то я очень сильно сомневаюсь, что оно будет правильно распознавать всякие сложные случаи, которых в этом треде уже много было. Ну или же придётся для такой элементарной задачи, как вырезание комментов, полностью описывать весь язык целиком.

Dasar

строки добавляются так:

program: (code|comment)*
comment = multi_line_comment | single_line_comment
multi_line_comment = '/*' any_char* '*/'
single_line_comment = '//' symbol* line_break
line_break = '\n' | '\r\n'
code: token|string) space)*
token: \w+
space: \b+
string: string1 | string2
string1: '\'' [^']* '\''
string2: '"' [^"]* '"'

kruzer25

А ещё надо помнить про то, что в строках могут быть escape-последовательности, что допустимы ещё и всякие запятые, скобки, плюсы-минусы итд... в результате, тебе придётся определять здесь полностью весь синтаксис языка, и будет очень больно, если что-нибудь забудешь. Тогда как мой код делает только то, что нужно - отбрасывает все комментарии (и ещё парой строчек добавляется правило "не рассматривать то, что внутри строк").

Dasar

> А ещё надо помнить про то, что в строках могут быть escape-последовательности, что допустимы ещё и всякие запятые, скобки, плюсы-минусы итд...
так у меня же написано, что любой символ кроме кавычки может быть внутри строки
если же речь идет о поддержке последовательности \' - то ее в любом случае надо добавлять, что в код, что в декларацию.
токен - это любая последовательность непробельных символов (за исключением кавычек соответственно все плюсы/минусы/скобки и т.д. - в это входит
фактически ты эти правила и описываешь, только на своем "птичьем" языке, а не в виде стандартной декларации

kruzer25

так у меня же написано, что любой символ кроме кавычки может быть внутри строки
Я неправильно выразился.
a=b*(c+d);

под твои определения вообще никак не подойдёт, там противоречий больше, чем символов.

Dasar

если хочешь, то могу к твоему код придраться.
1. Где у тебя вообще поддержка строк?
2. что будет, если надо будет добавить такие варианты строк:?
''''
""""
'\''
"\"'
3. что будет если надо добавить обработку ошибок?

Dasar

> под твои определения вообще никак не подойдёт, там противоречий больше, чем символов.
с точки зрения данной задачи - это один токен

Dasar

специально для тебя перепишу описание так (см. определение токена):

program: (code|comment)*
comment = multi_line_comment | single_line_comment
multi_line_comment = '/*' any_char* '*/'
single_line_comment = '//' symbol* line_break
line_break = '\n' | '\r\n'
code: token|string) space)*
token: любой_символ_кроме_пробельных_и_кавычек+
space: \b+
string: string1 | string2
string1: '\'' [^']* '\''
string2: '"' [^"]* '"'

kruzer25

Суть в том, что мне надо определить, что является комментариями (+ какие исключения из этого правила а тебе надо полностью описать весь язык.
Сейчас напишу окончательный полностью рабочий вариант.

Dasar

тебе надо полностью описать весь язык.
это ты так думаешь, а в моем описание - весь код (кроме строк и комментариев) - это один большой токен

kruzer25

Прошу прощения за говнокод, писалось в блокноте
<?php

abstract class StructureDescription {
public $sOpening;
public $sEnding;
public function __construct($sOpening, $sEnding) {
$this->sOpening = $sOpening;
$this->sEnding = $sEnding;
}
}

class StringDescription extends StructureDescription {
public $arrEscapeTokens;
public function __construct($sOpening, $sEnding, $arrEscapeTokens = array {
parent::__construct($sOpening, $sEnding);
$this->arrEscapeTokens = $arrEscapeTokens;
}
}

class CommentDescription extends StructureDescription {
public $sReplaceWith;
public function __construct($sOpening, $sEnding, $sReplaceWith = '') {
parent::__construct($sOpening, $sEnding);
$this->sReplaceWith = $sReplaceWith;
}
}

function stripComments($sCodeWithComments) {

$sCode = '';

$arrComments = array(
new CommentDescription('/*','*/',''
new CommentDescription('--',chr(0x0dchr(0x0d
new CommentDescription('--',chr(0x0achr(0x0a
);
$arrEscapeTokens = array(
// '\\\\0x[0-9a-f]{2}',
'\\\\.',
);
$arrStrings = array(
new StringDescription('\'','\'',$arrEscapeTokens
new StringDescription('"','"',$arrEscapeTokens
);

$bInComment = false;
$iCommentType = null;

$bInString = false;
$iStringType = null;

$l = strlen($sCodeWithComments);
for($i=0;$i<$l;$i++) {
if($bInComment) {
if(substr($sCodeWithComments,$i,strlen($arrComments[$iCommentType]->sEnding == $arrComments[$iCommentType]->sEnding) {
$bInComment = false;
$i += strlen($arrComments[$iCommentType]->sEnding) - 1;
$sCode .= $arrComments[$iCommentType]->sReplaceWith;
continue;
} else {
continue;
}
} else {
if($bInString) {
$sRest = substr($sCodeWithComments,$i);
$bMatched = false;
foreach($arrStrings[$iStringType]->arrEscapeTokens as $sEscapeToken) {
if(preg_match('/^'.$sEscapeToken.'/s',$sRest,$arrMatches {
$sCode .= $arrMatches[0];
$i += strlen($arrMatches[0]) - 1;
$bMatched = true;
break;
}
}
if($bMatched) continue;
if(substr($sCodeWithComments,$i,strlen($arrStrings[$iStringType]->sEnding == $arrStrings[$iStringType->sEnding]) {
$sCode .= $arrStrings[$iStringType]->sEnding;
$i += strlen($arrStrings[$iStringType]->sEnding) - 1;
continue;
}
$sCode .= substr($sCodeWithComments,$i,1);
continue;
}
foreach($arrStrings as $key => $oString) {
if(substr($sCodeWithComments,$i,strlen($oString->sOpening == $oString->sOpening) {
$bInString = true;
$iStringType = $key;
$sCode .= $oString->sOpening;
$i += strlen($oString->sOpening) - 1;
break;
}
}
if($bInString) continue;
foreach($arrComments as $key => $oComment) {
if(substr($sCodeWithComments,$i,strlen($arrComments[$key]->sOpening == $arrComments[$key]->sOpening) {
$bInComment = true;
$iCommentType = $key;
$i += strlen($arrComments[$iCommentType]->sOpening) - 1;
break;
}
if($bInComment) continue;
$sCode .= substr($sCodeWithComments,$i,1);
}
}
}
return $sCode
}
?>

Обрати внимание, что я тут не имею ни малейшего представления о том, как устроен язык за пределами комментариев и строк (да и на строки смотреть приходится только потому, что комменты, которые в них - не комменты.

kruzer25

program: (code|comment)*
comment = multi_line_comment | single_line_comment
multi_line_comment = '/*' any_char* '*/'
single_line_comment = '//' symbol* line_break
line_break = '\n' | '\r\n'
code: token|string) space)*
token: любой_символ_кроме_пробельных_и_кавычек+
space: \b+
string: string1 | string2
string1: '\'' [^']* '\''
string2: '"' [^"]* '"'
Я тебя поздравляю.
И как же ты собираешься понять,
/*test*/
- это code или comment?

Dasar

> как же ты собираешься понять,
подходит под правило multi_line_comment - значит комментарий

kruzer25

Нифига, подходит под правило token - значит, код.

hwh2010

code: (token space)*
space-то что? Совсем не обязательно, что вокруг строки whitespace'ы стоят!

Dasar

это вот одна из тех неточностей, с которой не хотелось разбираться

kruzer25

И, кроме того - это не критическая неточность.

Dasar

> Нифига, подходит под правило token - значит, код.
давай для простоты (хотя можно делать и хитрее) договоримся, что если между правилами есть конфликт, то выбирается первое.
критические неточности на твой взгляд еще есть?

kruzer25

критические неточности на твой взгляд еще есть?
Да.
У тебя там написано
(code|comment)*
Где тут конфликт между _двумя_ правилами?
a /*b*/ c
можно представить как code comment code, как code code code, двумя способами как code code, и как code. И как же понять, как правильнее?

tokuchu

правильное описание - это что-то типа:
program: (code|comment)*
comment = multi_line_comment | single_line_comment
multi_line_comment = '/*' any_char* '*/'
single_line_comment = '//' symbol* line_break
line_break = '\n' | '\r\n'
code: (token space)*
token: \w+
space: \b+
вот с таким описанием уже можно работать, и вот на такое описание и стоит тратить свое время.
заморочки же с регекспами или с чистым кодом - не стоят потраченного на них время.
Почему ты утверждаешь, что оно единственно правильное и не стоит заморачиваться регэкспами? Небольшой экскурс в теорию компиляторов и формальных грамматик:
Детерминированный конечный автомат без памяти не может матчить КС-грамматику. А когда говорят автомат, то подразумевается именно автомат без памяти.
Текст программы сначала разбивается на лексемы, а синтаксис строится уже поверх лексем. Обычно лексемы описываются только регулярными языками, а синтаксис - контекстно-свободными.
Это делается из-за того, что матчить регулярный язык можно за линейное время и O(1) памяти, а КС - уже за нелинейное в общем случае (нужно извращаться не меньше чем с регэкспами и строить LR и подобные). Именно поэтому и надо заморачиваться с регэкспами.
Упомянутый lex - как раз и занимается 1-й задачей - разбить текст на лексемы. Если ты хочешь полноценные языки описывать, то тебе уже синтаксические анализаторы понадобятся, типа yacc, bison.
В общем, для данной задачи, использование КС - избыточно и регулярные выражения/конечные автоматы и так легко и прекрасно с этой задачей справятся. В данной задаче нужно просто отфильтровать лексемы.

Dasar

Почему ты утверждаешь, что оно единственно правильное и не стоит заморачиваться регэкспами?
оно наиболее эффективное по затратам сил и времени (а не единственное правильное)
ps
кстати как много ты можешь привести качественных решений, использующие парсеры на основе регексов?
имхо, регекс - это хрень, для быстрого создания низкокачественного неподдерживаемого решения.

tokuchu

оно наиболее эффективное по затратам сил и времени (а не единственное правильное)
А я утверждаю, что на конечном автомате/регэксе более эффективно по тем же параметрам. :)
Кому верить? :)
кстати как много ты можешь привести качественных решений, использующие парсеры на основе регексов?
имхо, регекс - это хрень, для быстрого создания низкокачественного неподдерживаемого решения.
Ээээ.... так уже сколько раз повторял - лексемы большинства языков программирования описываются регулярными выражениями.

kruzer25

Кстати, я так и не увидел решения данной задачи на preg_replace. Даже если забыть о существовании строк, в которых то, что кажется комментами, таковыми не является.

Dasar

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

tokuchu

так вот именно, что отдельные лексемы, а не вся грамматика.
Ну так естественно. Т.к. грамматику языка программирования (не рассматривая отдельные исключения) просто невозможно описать регэкспом, но не из-за того, что регэксп предназначен для "грязных, кратковременных решений", а потому что регэксп - это средство из мира регулярных грамматик, а у языка синтаксис описывается контекстно свободной.
И даже этот факт, что для описания языка всё равно нужен КС-парсер не уменьшает "пользу", приносимую регулярными грамматиками.

Dasar

дык, зло в regexp-ах, а не в самих регулярных грамматиках

tokuchu

дык, зло в regexp-ах, а не в самих регулярных грамматиках
А в чём зло-то?
Вот, как минимум лексические анализаторы lex, flex используют такую нотацию. Не удивлюсь, если в других системах генерации компиляторов тоже используются они.
Многие утилиты обработки текста используют регулярные выражения.
Да и в теории компиляторов на ВМК даже преподаются алгоритмы построения ДКА по регулярному выражению.
Что ты можешь предложить для обработки текста, что было бы удобнее, если говоришь, что регулярные выражения зло?

Dasar

> если говоришь, что регулярные выражения зло?
зло именно regex - а именна та реализация (та нотация что пошла с перла
сами по себе регулярные выражения полезны и записывать их лучше в виде того же Бэкуса-Наура

tokuchu

зло именно regex - а именна та реализация (та нотация что пошла с перла
А вот и нет. Там где я говорил про регулярные выражения (lex, теория) имелись в виду как раз подобные перловским. Ну там на самом деле особо мудрить и не получится, т.к. они всё равно идеологически все будут похожи.
сами по себе регулярные выражения полезны и записывать их лучше в виде того же Бэкуса-Наура
А вот формы Бэкуса-Наура уже не особо похожи на регулярные выражения. Они больше напоминают запись (в общем случае) КС-грамматики. А писать регулярную грамматику сложнее, чем регулярное выражение. Вот, например, грамматика, которую ты писал - не является регулярной.

tokuchu

Кстати, я так и не увидел решения данной задачи на preg_replace. Даже если забыть о существовании строк, в которых то, что кажется комментами, таковыми не является.
Ну от себя могу предложить только вот такое. (Долго не думал, так что это не идеальное решение, т.е. это не повод обобщать его убогость на весь мир :) )
Имеем такие регулярные выражения:

комментарий: /\*.*?\*/|--.*?\n
строка: "([^"]|""|\\")*"
символ: .

Псевдокод:

if (/^${комментарий}/)
{
skip;
}
else
{
/^(${строка}|${символ})/
print;
}

tokuchu

а именна та реализация (та нотация что пошла с перла
Кстати, по поводу нотаций. Базовое в регулярных выражениях только: группировка - альтернатива - |, повторение - *. Всё остальное - syntax sugar и в этом ничего плохого нет. Разве только есть всякие нерегулярные расширения типа некоторых видов бектресинга, но это уже отдельный предмет обсуждения.
Так что именно тебе в перловской нотации не нравится?

bleyman

Кстати, я так и не увидел решения данной задачи на preg_replace. Даже если забыть о существовании строк, в которых то, что кажется комментами, таковыми не является.
Эм. Чувак, я вообще-то написал совершенно полное решение, с корректной обработкой строк и всем таким. Только оно либо удалит все комменты за квадратичное время, либо нужно будет его ещё раз взять в скобки и поставить звёздочку, чтобы потом ручками вытащить и сконкатенировать все матчи из группы. Ничего лучше сделать нельзя, потому что для определения того, является ли произвольный данный кусок кода комментом, нужно прочитать весь предыдущий код, а встроенной объединялки различных матчей одной и той же группы в стандартном реплейсе практически наверняка нет.

Dasar

Так что именно тебе в перловской нотации не нравится?
также regex-ы неудобны с эксплуатационной точки зрения:
1. нет повторного использования
2. нет разбиения на отдельные части
3. нет группового отделения команд от текста
4. предыдущие пункты + более мелкие - приводят к низкой читабельности regex-ов, что приводит к большому кол-ву ошибок в них

bleyman

2Даркгрей и Грин: я что-то не пойму, вы это тупите так дружно, или на самом деле не понимаете?
Лексу на вход подаётся набор "регулярка" - "действие". Он объединяет все регулярки в один конечный автомат, хитроумно разруливая неоднозначности/специализации (типа что я могу написать регулярку для комментов, ниже — регулярку для токенов (по идее матчащую и комменты тоже а он при объединении сделает так, что токен будет матчится только если до того не заматчился коммент (этого не мог понять пенартурег, известно почему!.
Точнее синтаксиса я не знаю, возможно он даже позволяет писать что-то БНФ-подобное, но БНФом не являющееся (достаточно запретить рекурсию).
Вот! Эта штука позволяет разбивать регекс на маленькие именованные независимые кусочки, что очень хорошо. Но получается в результате тот же самый регекс, что, кстати, ещё лучше! Правда, на этом повод для спора исчёрпывается?

tokuchu

Лексу на вход подаётся набор "регулярка" - "действие". Он объединяет все регулярки в один конечный автомат, хитроумно разруливая неоднозначности/специализации (типа что я могу написать регулярку для комментов, ниже — регулярку для токенов (по идее матчащую и комменты тоже а он при объединении сделает так, что токен будет матчится только если до того не заматчился коммент (этого не мог понять пенартурег, известно почему!.
И где я туплю? Я где-то утверждал обратное?

tokuchu

1. нет повторного использования
Поясни. Чего тебе повторно использовать надо?
2. нет разбиения на отдельные части
Опять поясни чего ты разбивать хочешь?
3. нет группового отделения команд от текста
Что есть команды и текст? *, |, [] - это команды? Их ты хочешь отделить от текста? Что значит "групповое отделение"?
4. предыдущие пункты + более мелкие - приводят к низкой читабельности regex-ов, что приводит к большому кол-ву ошибок в них
Не пиши большие регекспы, а пиши маленькие и объединяй их потом. :)
Когда ты пишешь код на своём любимом ЯП, то там тоже, если напишешь функцию больше чем на страницу - она станет нечитабельной. Это проблема ЯП? Отчасти да, т.к. может есть ЯП, где можно записать короче, но ты ведь из-за этого не отказываешься от этого ЯП.

bleyman

Ты не понимал ДаркГрея! И спорил не с ним, а со своим непониманием! Это называется "тупить"!
Вот кстати я теперь стал неуверен, а самому проверять влом: это я правду написал про разруливание специализаций? Или всё-таки нужно в явном виде запретить токену начинаться с комментосимволов, например? Просто как бы оно же конечный автомат, поэтому если оно, например, считывает строчку "/*abc ", ему нужно сразу решить, это токен (и его нужно вернуть) или потенциальное начало коммента (и тогда надо читать дальше). А не слишко ли много он на себя возьмёт, если самостоятельно запретит такие токены?

tokuchu

Ты не понимал ДаркГрея! И спорил не с ним, а со своим непониманием! Это называется "тупить"!
Хрена се. Может ты не понимаешь чего он имеет в виду? По крайней мере мне (и надеюсь ему) наша дискуссия кажется осмысленной. Он утверждает, что описывать регулярные грамматики посредством регулярных выражений неудобно. А я ему доказываю, что все так делают и что это более удобный способ, чем остальные. Пока конкретно не покажешь где я по-твоему туплю - я буду считать, что ступил ты. :)
Вот кстати я теперь стал неуверен, а самому проверять влом: это я правду написал про разруливание специализаций? Или всё-таки нужно в явном виде запретить токену начинаться с комментосимволов, например? Просто как бы оно же конечный автомат, поэтому если оно, например, считывает строчку "/*abc ", ему нужно сразу решить, это токен (и его нужно вернуть) или потенциальное начало коммента (и тогда надо читать дальше). А не слишко ли много он на себя возьмёт, если самостоятельно запретит такие токены?
flex вроде себя ведёт так: прочитывает очередную самую длинную возможную лексему, а если она подпадает под несколько вариантов, то берёт тот, что встречается раньше в списке.

bleyman

Он утверждает, что описывать регулярные грамматики посредством регулярных выражений неудобно
---
Ты уверен, что правильно понимаешь, что он имеет в виду?
Он утверждает (и я с ним согласен что неудобно описывать регулярную грамматику при помощи одного длинного регулярного выражения, из которого, после очередного матча, можно вытащить содержимое надцатой скобки и, если оно не пусто, считать, что распозналась соответствующая лексема, иначе проверить содержимое надцатьпервой скобки и далее. Ну это реально неудобно, не правда ли?
В качестве альтернативы он предлагает использовать мета-язык поверх регулярных выражений, позволяющий описывать грамматику небольшими независимыми кусочками (которые, тем не менее, компилируются в одну большую регулярку). И ты предлагаешь то же самое! Это означает, что вы друг друга не понимаете, не правда ли?
flex вроде себя ведёт так
---
Эм. А как это работает? Вот в данном случае, если коммент — это любые символы внутри скобок, а токен — это любые символы до пробела. Оно видит открывающую скобку и какие-то символы, читает, читает, потом хуяк, кончается файл. Тогда оно должно понять, что ему следовало бить на токены, вернуться и продолжить, но тогда это уже совсем не конечный автомат. А если найдёт закрывающую скобку, то следует вернуть коммент. Не понимаю!

tokuchu

Он утверждает (и я с ним согласен что неудобно описывать регулярную грамматику при помощи одного длинного регулярного выражения, из которого, после очередного матча, можно вытащить содержимое надцатой скобки и, если оно не пусто, считать, что распозналась соответствующая лексема, иначе проверить содержимое надцатьпервой скобки и далее. Ну это реально неудобно, не правда ли?
А, ну это если собирать всё в одно. Это конечно не тот вариант, тут соглашусь. Но тут всё же имеем не один регулярный язык, а набор (язык, представляющий комментарии, язык представляющий строки, ...). Получается некоторое искажённое применение и из-за этого возникает геморрой. :)
Тут надо смотреть задачу. Для компиляторов (и не только) - есть lex, который позволяет строить такие автоматы.
Эм. А как это работает? Вот в данном случае, если коммент — это любые символы внутри скобок, а токен — это любые символы до пробела. Оно видит открывающую скобку и какие-то символы, читает, читает, потом хуяк, кончается файл. Тогда оно должно понять, что ему следовало бить на токены, вернуться и продолжить, но тогда это уже совсем не конечный автомат. А если найдёт закрывающую скобку, то следует вернуть коммент. Не понимаю!
Ну для такого там, видимо, что-то вроде ungetc применяется. Сейчас поставил эксперимент - маленький файл разбил на токены при незакрытом комментарии, а скормил большой ~50MB - очень надолго задумался, пока ещё не отошёл. Бегло проглядел документацию - конкретно про эту проблему не нашёл, но там можно сделать что-нибудь вроде:
".*<EOF> print "Незакрытая строка"

kruzer25

И чем вот это конкретное решение принципиально отличается от моего варианта?
Я же говорил про те решения, которые состоят из одного длинного preg_replace, вроде
return preg_replace('/(\\/\\*.*\\*\\/|\\/\\/.*[\\r\\n])/s','',sCodeWithoutComments);
(с которым, кстати, даже если не думать о гадостях вроде вложенных комментов, неподготовленному читателю/писателю надо ещё долго думать, чтобы понять, где тут писать .*, где .*?, где [^\\r\\n]* и с какими ключами писать это регулярное выражение, чтобы оно захавало не так много, как смогло, а, наоборот, так мало, как только можно).
(Я правильно понимаю, что то, что ты написал - надо завернуть в цикл?)

kruzer25

Чувак, я вообще-то написал совершенно полное решение, с корректной обработкой строк и всем таким.
Ты про
^(?'capture' "[^"]*") | (?[^\n\r]*
?
Я не отношусь к категории людей, которые общаются на многоэтажных регэкспах, целиком ниасилил, но двойку тебе можно поставить сразу, хотя бы только за это:
("[^"]*")
Так что давай, исправляй такие ошибки - а потом, если у тебя это получится, посмотрим на размер и читабельность твоего выражения (навряд ли они будут лучше, чем сейчас).

Dasar

> Поясни. Чего тебе повторно использовать надо?
один и тот же кусок регулярного выражения - два раза
> Опять поясни чего ты разбивать хочешь?
одно большое регулярное выражение
> Что есть команды и текст? *, |, [] - это команды? Их ты хочешь отделить от текста? Что значит "групповое отделение"?
например, один раз сказать, что вот этот кусок - текст, или вот этот кусок - команды
обычно это делается через те же кавычки
вот такая запись в отличие от стандартного regex-а, и делает разбиение регулярного выражения на три группы с помощью пробелов, и с помощью кавычек отделяет текст от команд:
'/*' .* '*/'
> Не пиши большие регекспы, а пиши маленькие и объединяй их потом
так именно про это я и толкую, что regex - зло, потому что не позволяет так делать.
т.к. объединять их на уровне своего любимого языка - это многое потерять от регулярных выражений, сразу начинают идти множественные проходы по строке, самому надо разбираться с вариантами, бактракингом и т.д.
соответственно хочется цеплять regex-ы вместе на каком-нибудь спец. мета языке, например, на том же бэкусе-науре
ps
_FJ как раз правильно передал своими словами мою позицию

bleyman

но двойку тебе можно поставить сразу, хотя бы только за это
lolwut?
Если что, я его оттестил на разных примерах. Он работает. Синтаксис .net regex engine с врубленными настройками singleline, ignore whitespaces, compiled (может, ещё что забыл). Проверял в Expresso.

Marinavo_0507

> та реализация (та нотация что пошла с перла
ггг

bleyman

Кстати, если добавить комментов и отступов, то даже читабельно =)
EDITED: а ещё в нём мог быть баг с поеданием кавычки как обычного символа, так что добавил и её туда
EDITED2: Ах, если хочется эскейпов внутри строчки (а не только паскаль-стайл вложенные кавычки, как в sql, то так) (и заодно тогда пусть все кавычки будут single, а не double, раз уж мы про sql!спасибо, Мадкроз!)
   
^
(?'capture' # chunk of code before comment
(
(' ([^'\\] | \\.)* ') # quoted string
|
(?!-- | /\* ) [^'] # any char (not starting a comment or quote)
)*
)

(
( /\* ?!\*/).)* \*/ ) # multiline comment
|
(--[^\n\r]*) # singleline comment
)

karkar

И что выдается на такой строчке
comments around strings: aaa /* 'd/*ee*/d --fff' */ aaa

?

bleyman

match: aaa /* 'd/*ee*/
"capture": aaa
Я таки не понял, что ви имеете в виду.

karkar

Возможно, я плохо понял предлагаемое решение. Твой регексп находит две весчи - все до первого коммента и сам первый коммент. Я правильно понимаю, что общий алгоритм - в последовательном применении этого регекспа с вырезанием найденного коммента? Если да, то он вырежет не то, что хотелось бы.
Вообще, хотелось бы увидеть законченное решение, которое можно запустить, натравить на некий файл и увидеть результат. Я выше приводил тест, мне кажется, результат тут будет другим.

tokuchu

И чем вот это конкретное решение принципиально отличается от моего варианта?
Я же говорил про те решения, которые состоят из одного длинного preg_replace, вроде
return preg_replace('/(\\/\\*.*\\*\\/|\\/\\/.*[\\r\\n])/s','',sCodeWithoutComments);
(с которым, кстати, даже если не думать о гадостях вроде вложенных комментов, неподготовленному читателю/писателю надо ещё долго думать, чтобы понять, где тут писать .*, где .*?, где [^\\r\\n]* и с какими ключами писать это регулярное выражение, чтобы оно захавало не так много, как смогло, а, наоборот, так мало, как только можно).
Извини, но твоё решение я не смотрел или не помню уже. Просто ответил на поставленный тобою вопрос. Можно, наверное, написать решение из одного длинного выражения, которое будет сразу выводить текст перед очередным комментарием (вроде как раз то, что fj делает но его всё равно придётся применять в цикле.
(Я правильно понимаю, что то, что ты написал - надо завернуть в цикл?)
Да, несомненно. Без цикла решить эту задачу просто невозможно. Ключ "g" в регулярном выражении - тот же самый цикл.

tokuchu

>> Поясни. Чего тебе повторно использовать надо?
> один и тот же кусок регулярного выражения - два раза
Можно. В perl как минимум.
>> Опять поясни чего ты разбивать хочешь?
> одно большое регулярное выражение
Разбивать куда? Пример желаемого можно?
>> Что есть команды и текст? *, |, [] - это команды? Их ты хочешь отделить от текста? Что значит "групповое отделение"?
> например, один раз сказать, что вот этот кусок - текст, или вот этот кусок - команды
обычно это делается через те же кавычки
> вот такая запись в отличие от стандартного regex-а, и делает разбиение регулярного выражения на три группы с помощью пробелов, и с помощью кавычек отделяет текст от команд:
> '/*' .* '*/'
Предложение интересное. Хз... может что и есть такое, не думал над этим. Может такого нет из-за того, что не стоит писать большие регулярные выражения. :) Потом, в том же perl, например, можно строки вставлять через переменные - они уже смогут содержать любые символы, хотя для маленьких кусков текста это не будет удобно, наверное.
>> Не пиши большие регекспы, а пиши маленькие и объединяй их потом
> так именно про это я и толкую, что regex - зло, потому что не позволяет так делать.
> т.к. объединять их на уровне своего любимого языка - это многое потерять от регулярных выражений, сразу начинают идти множественные проходы по строке, самому надо разбираться с вариантами, бактракингом и т.д.
Нет, просто ты хочешь от инструмента того, для чего он не предназначен. :) Наверное они просто так хорошо делает именно свою работу, что хочется их обобщить на близкие задачи. :)
Ну то есть я хочу сказать, что ты не прав, говоря, что они - зло. Правильнее было бы сказать, что отстойно то, что нет какого-нибудь распространённого общепринятого способа "мультиплексирования" регэкспов. Но сами эти способы, вообще говоря, есть - тот же flex, perl, sed, ...
> соответственно хочется цеплять regex-ы вместе на каком-нибудь спец. мета языке, например, на том же бэкусе-науре
Формы бэкуса-наура трудно представить как сюда подойдут, т.к. они описывают КС-грамматики, а тебе нужно что-то более "линейное". Если тебе КС нужны - то смотри генераторы синтаксических анализаторов. И будет тебе регуляки+КС. Но из-за отсутствия КС в регулярных выражениях, называть их злом ещё более неверно. :)

tokuchu

Вот сейчас подумал - наверное на sed это реально выглядело бы достаточно просто.

bleyman

А какой результат ты хочешь? Твой пример разберётся так (проверял полуавтоматически, экспрессой, компилить и заливать полное решение по-прежнему влом):
aaa /* 'd/*ee*/d --fff' */ aaa
aaa d --fff' */ aaa
aaa d
И это, по-моему, совершенно правильно. Комменты не бывают вложенными, по крайней мере ни в одном из известных языков мне такого ужаса нет.
Да, и ещё, мне кажется, или твой код вообще-то КС-грамматику разбирает? Он же кавычки парно матчит?

kruzer25

Если что, я его оттестил на разных примерах. Он работает.
Проверка:
"\""

kruzer25

Кстати, мегажесть, наследие старых времён, мы пытаемся это не трогать даже восемнадцатиметровой палкой. Одно из регулярных выражений, которое используется в шаблонизаторе:
~\{/{0,1}?:\^?\$|%\w+(?:\[(?:\d+|(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|\w[\w\d]*|(?:\^?\$|%)\w[\w\d]*(?:\.?(?:\^?\$|%)\w[\w\d]*)*(?:\.\w[\w\d]*)*)\])*(?:\.(?:\^?\$|%)?\w+(?:\[(?:\d+|(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|\w[\w\d]*|(?:\^?\$|%)\w[\w\d]*(?:\.?(?:\^?\$|%)\w[\w\d]*)*(?:\.\w[\w\d]*)*)\])*)*(?:(?:[\+\*\/\%]|(?:-(?!>?:(?:\-?\d+(?:\.\d+)?)|[\$\w\.\+\-\*\/\%\d\>\[\]])*)?:\|@?\w+(?::(?:\w+|(?:\-?\d+(?:\.\d+)?)|?:\^?\$|%\w+(?:\[(?:\d+|(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|\w[\w\d]*|(?:\^?\$|%)\w[\w\d]*(?:\.?(?:\^?\$|%)\w[\w\d]*)*(?:\.\w[\w\d]*)*)\])*(?:\.(?:\^?\$|%)?\w+(?:\[(?:\d+|(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|\w[\w\d]*|(?:\^?\$|%)\w[\w\d]*(?:\.?(?:\^?\$|%)\w[\w\d]*)*(?:\.\w[\w\d]*)*)\])*)*(?:(?:[\+\*\/\%]|(?:-(?!>?:(?:\-?\d+(?:\.\d+)?)|[\$\w\.\+\-\*\/\%\d\>\[\]])*)?)|(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*'*)*)/{0,1}\}~

slonishka

wenn ist das nunstuck
geht und slotermeyer?
ja! ba yerhund das oder
die flipperwaldt gespuhrt!
:grin: :grin:

bleyman

Чукча не читатель?
В той версии эскейпов предусмотрено не было, подразумевалось, что кавычки квотятся удвоением. И, кстати, Мадкроз сказал, что прочитал в интернетах, что эскейпов в sql нет, а есть в postgressSQL (хотя в интернетах пишут неправду, да и Мадкроз тоже - - -).
Тем не менее в продвинутой версии я эскейпы добавил.

karkar

> А какой результат ты хочешь?
Хочу ааа ааа.
Мне кажется странным в твоем дизайне, что комментарий не может начинаться внутри строки,
но может в ней заканчиваться. Что строки могут содержать комментарии, когда они - часть
кода, но не могут, когда их самих закомментили. Получается, что или мы не можем закомментить
произвольную часть кода, или не можем иметь комментарии внутри строки.
>Комменты не бывают вложенными, по крайней мере ни в одном из известных языков мне
такого ужаса нет.
В SQL комменты действительно не могут быть вложенными, но вот прозрачны ли там строки -
не знаю. А "такой ужас", как вложенные комменты, есть в том же окамле.
>Да, и ещё, мне кажется, или твой код вообще-то КС-грамматику разбирает?
> Он же кавычки парно матчит?
Встретив кавычку, переходит в состояние Строка и остается в нем до встречи следующей такой
же кавычки. Про КС не скажу, третий курс давно был. :)

Dasar

Получается, что или мы не можем закомментить
произвольную часть кода,
да, не можем

bleyman

Ну вот так вот устроены комментарии во всех мейнстримных языках, даже в sql-е, извините =) Задача стояла вполне чётко и получается, что твоя программа её не решает.
Я не хочу начинать флеймвор на такую дурацкую тему, но, по-моему, традиционный парсинг комментов правилен.
Особой пользы от вложенных комментов я не вижу. Двух видов комментов в сочетании с нормальным, позволяющим (un)comment selection редактором вполне хватает на маленькие штуки, а если нужна штука больше, то лучше всё-таки уже воспользоваться специально для этого предназначенной системой контроля версий.
Комменты внутри строк... Ну это вообще маразм, по-моему. Польза крайне сомнительна, зато геморроя добавится немало.
Ну да, кажется, что получилось немножко неортогонально. Если подумать, то ещё очень большой вопрос, знаешь ли, это на самом деле так, или кажется. Ты смотришь на комменты и кавычки и видишь КС-язык типа математических скобок, поэтому несбалансированности тебе кажутся странными. А зачем ты так смотришь? Вложенные кавычки бессмысленны. Нет в них смысла вообще ни одного. Ты их можешь сколько угодно оформлять наподобие операторных скобок, смысл от этого не появится. Вложенные комменты, в общем-то, тоже. Либо код компилируется, либо нет. Ну и получается, что простой конечный автомат, линейно проходящий по тексту и раскрашивающий его в разные "цвета" является вполне удовлетворительной мысленной моделью. Не, остаются, конечно, неудобные нелогичные штуки, вроде нелокальности: поставив кавычку (или коммент) в начале программы ты непредсказуемо и весьма забавно перекрашиваешь её всю. Но КС-грамматика от этого не спасает.

karkar

Ты прав. Сейчас проверил в MySQL, C# и C++, везде коммент не может начаться внутри строки, но может в ней закончиться.
Не очень понял про вложенные кавычки и комменты и мой код. Мой вариант отличается по поведению от твоего только тем, что строки непрозрачны внутри комментов, что строк несколько видов (см. синтаксис PL/SQL и что все обрабатывается за один проход. Вложенных комментов и строк у меня нет. Никаких грамматик, просто конечный автомат.

bleyman

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

evgarus

Сейчас проверил в MySQL, C# и C++, везде коммент не может начаться внутри строки, но может в ней закончиться.

В смысле если я напишу на c++
i = 0; //hui
то у меня будет ошибка компиляции?

karkar

Если напишешь
i=0; /* "hui */ " */
то будет.

evgarus

ну так а чего проверять-то, каммент заканчивается на первых */ :)

slonishka

я тоже перестал понимать содержание постов в этом топике после регекспа, который запостил пенартур.

evgarus

Я решил пропустить содержание этих постов :)

kruzer25

Бля, +1 :o
МБ мой регэксп разрушил их мозг? :D

0000

Пришел таки на работу, первым делом рещил проверить exe от . Где то бага, поскольку на выходе фигня получилась :(
Теперь хочу проверить код от и .
Что там надо установить подскажите плиз (т.е. что для пых-пыха надо?)

karkar

Вот еще вариант: http://stuff.thedeemon.com/nocom2.exe (исходник там же).
Исправил один баг со звездочкой и сделал строки прозрачными внутри комментов, как обсуждали выше. Если после этого будут глюки, то скорее всего из-за отсутствия обработки escape-последовательностей.

kruzer25

Что там надо установить подскажите плиз (т.е. что для пых-пыха надо?)
php.net.
Но вообще, у меня сильное подозрение, что мой код может быть с лёгкостью переписан для любого высокоуровнего языка такого типа, например, C# или Java ;)
Возможно, с этим даже справился бы машинный переводчик, даже на тех же регэкспах ;)

karkar

Оказалось, дело в моей ошибке при обработке конструкций типа /*****/.
Исправленный вариант: http://stuff.thedeemon.com/nocom2.exe (исходник там же).

0000

Псиб.
Пока вопрос закрыт - использую прогу от :)
Оставить комментарий
Имя или ник:
Комментарий: