LINUX.ORG.RU

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

 ,


0

2

В очередной раз на грабли наступил.

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

Плюешь и начинаешь просто честный парсер писать в этом месте. Не на регулярках.

Очередные грабли в том,что в двухэтажные и кое-как отлаженные регулярки надо еще добавить, что искомые выражения могут разрываться переводами строки. Ну к примеру, ищешь в качестве образца слово SPAN, а оно может оказаться и S\nPAN и S\n\PA\nN и короче после любого символа может оказаться перевод строки. Или несколько переводов строки.

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

★★★★★

Последнее исправление: praseodim (всего исправлений: 1)

Поздравляю вас с прозрением.

X512 ★★★★★
()

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

Намного лучше писать парсер на Си, сам всегда так делаю когда что-то сложнее поиска простой строки в потоке.

firkax ★★★★★
()

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

AKonia ★★★
()
Ответ на: комментарий от Shushundr

вполне себе можно с помощью регулярок парсить что-то примитивное типа json. html то же можно. у него просто регулрки неправильные

</?[a-z]+(\s+\w+\s*=\s*("([^"]|\\")*"|'([^']|\\')*')\s*)*>

tz4678_2
()
Ответ на: комментарий от firkax

Курицу можно научить считать до 4, но не больше. Значит, число 5 не нужно.

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

Partisan ★★★★★
()
Ответ на: комментарий от firkax

Намного лучше писать парсер на Си, сам всегда так делаю когда что-то сложнее поиска простой строки в потоке.

какая разница на каком языке? Сишный strings более-менее реализован в других языках. И, честно говоря, не так уж и удобен

adn ★★★★
()

Древнейший письменный памятник, возраст которого оценивается в 30000 лет, недавно был расшифрован, оказалось, что «Ыых угу ага ха гыы аргх мгха фруу» означает «не пишите парсеров на регулярках».

gremlin_the_red ★★★★★
()
Последнее исправление: gremlin_the_red (всего исправлений: 1)
Ответ на: комментарий от adn

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

firkax ★★★★★
()
Ответ на: комментарий от tz4678_2

вполне себе можно с помощью регулярок парсить что-то примитивное типа json

Нельзя. Регулярки не умеют считать скобки.

html то же можно. у него просто регулрки неправильные

Тоже нельзя. А с появлением в html5 кастомных тегов его грамматика стала контекстно-зависимой.

Laz ★★★★★
()

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

pfg ★★★★★
()

Для парсинга не подходит. Но куча кодеров пишут CRUD’ы и Regex там нужен для валидации значений вводимых пользователями. Так же он пригодиться когда нужно сделать большую автозамену.

Aber ★★★★★
()
Ответ на: комментарий от tz4678_2

ты мягкое с теплым путаешь (а говно и теплое и мягкое)

tz4678_2
()
Ответ на: комментарий от tz4678_2

вполне себе можно с помощью регулярок парсить что-то примитивное типа json. html то же можно. у него просто регулрки неправильные

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

В общем, реальная программа - это 1% исходного алгоритма и 99% обработки исключений =) Ну может 10/90...

praseodim ★★★★★
() автор топика
Ответ на: комментарий от pfg

не удобнее что его код надо написать и допилить до рабочего состояния.

Да, в отличие от готовых регэкспов, его надо допиливать в каждом конкретном случае. Это потеря времени и сил. Зато потом легче всякие дурацкие нестандартности обрабатывать.

praseodim ★★★★★
() автор топика
Ответ на: комментарий от gremlin_the_red

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

Когда у меня финальную строку с выражением-регуляркой стала генерировать отдельная функция и в ней в свою очередь для этой генерации применены регулярки, возникло ощущение, что это говнокодище.

praseodim ★★★★★
() автор топика
Ответ на: комментарий от firkax

В Си это делается простым инкрементом указателя.

не особо простым - у тебя может быть в строке utf-8 например

и ты действительно ищешь побайтно поледовательность? с кучей ветвления?

adn ★★★★
()
Последнее исправление: adn (всего исправлений: 1)

Ken Thompson (Jun 1968). «Programming Techniques: Regular expression search algorithm». Communications of the ACM. 11 (6): 419–422

следует помнить что конечный автомат удобный по месту инструмент

когда же из него делают почти полный тьюринг это по сильнее брэйнмассажа

qulinxao3 ★★
()
Ответ на: комментарий от adn

можем позавидовать счастливчику ему еще предстоит познать боера-мура и прочие кнутства

qulinxao3 ★★
()

ищешь в качестве образца слово SPAN, а оно может оказаться и S\nPAN и S\n\PA\nN и короче после любого символа может оказаться перевод строки

Тут такая херня: «регулярный» означает «повторяющийся». Если у тебя нет повторяющихся выражений, то ну. Сам подумай.

Или хотя бы просунь текст сквозь какой нибудь санитайзер для начала, это проще, чем навалиавать еще больше (.*(!*({}(.*^[{.}?{}])*$.

thesis ★★★★★
()
Последнее исправление: thesis (всего исправлений: 1)

в чём вопрос непонятно, но пост понятный и правильный. Регулярка длиннее символов 10 превращается в боль при переключении между людьми.

max_lapshin ★★★★★
()

В моих задачах регулярные выражения вполне себе полезны и не разрастаются. Ну если разрастется, заменю чём-нибудь. Парсер мне за последние годы вообще понадобился ровно один раз. И то я там выпендриться решил — поддержать полноценный скл. Сейчас бы сделал структурированным жсоном.

vbr ★★★★
()

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

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

И между прочим тормозит.

А ты хочешь сказать что руками напишешь конечный автомат эффективнее чем тебе движок регулярок скомпилирует?

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

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

Плюешь и начинаешь просто честный парсер писать в этом месте. Не на регулярках.

Это нет смысла противопоставлять регуляркам (особенно в плане производиттельности). Во-первых, парсер обычно работает с лексером который регулярки, во-вторым сам для некоторых типов грамматик работает как конечный автомат (только в алфавите лексем а не байт/символов). Для других типов грамматик алгоритм другой, но похожий.

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

slovazap ★★★★★
()
Ответ на: комментарий от pfg

стандартная вилка «используешь готовый код - пишешь свой».

Нет, вилка «используешь готовый неподходящий код, подпираешь его тонной костылей, чтоб хоть как-то подходил» и «пишешь свой сразу подходящий». Затраты времени во втором случае не больше чем в первом, если распарсиваемая строка достаточно сложна.

firkax ★★★★★
()
Ответ на: комментарий от adn

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

и ты действительно ищешь побайтно поледовательность? с кучей ветвления?

Не очень понятен вопрос. Если надо тупо «найти последовательность» то это strstr() или его аналог для нуль-нетерминированных строк с явно заданной длиной, ветвления там не нужны (если переход с конца цикла в начало им не считать). Но парсер обычно не совсем этим занимается.

firkax ★★★★★
()
Ответ на: комментарий от thesis

Тут такая херня: «регулярный» означает «повторяющийся». Если у тебя нет повторяющихся выражений, то ну. Сам подумай.

Не значит. Слово «регулярный» в сочетании «регулярный язык» выбрано почти от балды и само по себе не значит ничего.

Waterlaz ★★★★★
()

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от pfg

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

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

удобнее что он узкозаточен. не удобнее что его код надо написать и допилить до рабочего состояния.

стандартная вилка «используешь готовый код - пишешь свой».

Вдвойне нет. Для написания парсеров есть другие готовые инструменты.

Waterlaz ★★★★★
()
Ответ на: комментарий от slovazap

А ты хочешь сказать что руками напишешь конечный автомат эффективнее чем тебе движок регулярок скомпилирует?

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

Это в каком же таком идиотском протоколе или формате разрешены переводы строк в любом месте?

html

firkax ★★★★★
()
Ответ на: комментарий от olelookoe

одна из зависимостей php… регулярки не нужны говорили неосиляторы

tz4678_2
()
Ответ на: комментарий от thesis

Или хотя бы просунь текст сквозь какой нибудь санитайзер для начала, это проще, чем навалиавать еще больше (.*(!*({}(.*^[{.}?{}])*$.

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

praseodim ★★★★★
() автор топика

Это же фича, в чем проблема?

Shadow ★★★★★
()
Ответ на: комментарий от slovazap

А ты хочешь сказать что руками напишешь конечный автомат эффективнее чем тебе движок регулярок скомпилирует?

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

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

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

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

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

praseodim ★★★★★
() автор топика
Ответ на: комментарий от firkax

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

Ну ragel например позволяет, описывая регулярку, добавить в неё код привязанный ко входу или выходу из состояния или к конкретному переходу в другое состояние. Что в итоге позволяет, по сути, сматчив регулярку, получить разу структуру распарсенных из неё данных с возможностями куда шире чем просто capture groups. При этом она остаётся обычной регуляркой с обычным КА под капотом.

html

Серьёзно? Где это написано?

slovazap ★★★★★
()
Ответ на: комментарий от praseodim

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

Ну вот именно на это был намёк. Тот же приснопамятный ragel позволяет писать структурированно, типа, условно

whitespace = [ \t]+;
newline = '\n' '\r'?;

// адрес электронной почты состоящий из имени пользователя и домена
username = [a-zA-Z.-]+;
domain = [a-zA-Z0-9-]+.[a-z0-9-]+;
email_address = username '@' domain;

// список адресов разделёных пробелом
email_address_list = (email_address whitespace)* email_address;

// тело письма
email_body = .*;

// заголовки
to_header = 'to'i whitespace ':' whitespace email_address_list;
cc_header = 'cc'i whitespace ':' whitespace email_address_list;
bcc_header = 'bcc'i whitespace ':' whitespace email_address_list;
header = to_header | cc_header | bcc_header;
headers = (header newline)*;

// основное правило для всего письма
email = headers newline email_body;

Причём в любом месте можно в {} написать кусок сишного кода в котором доступны указатели на начало и конец матча которые можно сразу сохранить в какой-нибудь

struct {
    vector<string_view> to;
    vector<string_view> cc;
    vector<string_view> bcc;
    string_view body;
}

и получить на выходе сразу распарсенное из, например,

To: bgates@microsoft.com
CC: foo@example.com bar@example.com
cc: baz@example.com

Hello, world!

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

А для более простых вещей хватит и capture groups которые если что, поддерживаются именованные в большинстве движков. Не знаю, правда, про массивы.

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

Это всё понятно, но я-то исхожу тоже из реального опыта.

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

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

sp = [ \t\n\r]*;
span = 's'i sp 'p'i sp 'a'i sp 'n'i;
number = ([0-9] sp)* [0-9];
message = sp span sp number sp;

Что сматчит span 123 независимо от того как тот разделён пробелами и переводами строк и даже от регистра и при этом грамматика вполне читабельна.

Есть правда, кейс когда нужно парсить откровенный мусор (и скорее всего это кейс парсинга HTML, когда есть и незакрытые тэги и забытые кавычки и прочая, хотя я не верю что тэги можно разбивать по середине), и там скорее нужен особый подход, но в основе всё равно будут регулярки, а как из них собрать что-то осмысленное в плане структуры документа наверняка есть какие-нибудь paper’ы от гугла или мозиллы.

slovazap ★★★★★
()

Плюешь и начинаешь просто честный парсер писать в этом месте. Не на регулярках.

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

theNamelessOne ★★★★★
()
Ответ на: комментарий от slovazap

При этом она остаётся обычной регуляркой с обычным КА под капотом.

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

Серьёзно? Где это написано?

Не.

firkax ★★★★★
()
Ответ на: комментарий от firkax

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

pfg ★★★★★
()

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

Всё сильно зависит от языка, в котором ты с регулярками работаешь. Тот же Perl позволяет использовать модификатор x (разбиваем регулярки на несколько строк) и интерполяцию строк в регулярках, что вместе очень сильно упрощает работу и повышает читабельность.

Да, это всё равно не решает проблему полностью, но очень сильно расширяет границы, в которых регулярки можно применять.

my $whitespace = '\s+';
my $string = '\S+';

foreach (`who`) {
	/
	(?<user> $string) $whitespace
	(?<tty> $string) $whitespace
	(?<date> $string)
	/x;

	say "$+{user} : $+{tty} : $+{date}"
}

Более того, не забывай, что встречается много разовых задач, которые нужно сделать «здесь и сейчас», например: клиент прислал CSV, из которого нужно взять 3 колонки, немного преобразовать и сгенерировать SQL скрипт для INSERT’а данных. Делается это один раз, после чего твой скрипт и CSV файл выкидываются. В таких задачах RegEx’ы бывают незаменимы.

runtime ★★★★
()
Последнее исправление: runtime (всего исправлений: 1)
Ответ на: комментарий от pfg

Ненормально, что недоквалифицированный программист этим как бы гордится. Работа программистом слишком сложная - иди работать олигархом. Для этого большого ума не нужно, и без регулярных выражений можно обойтись. Нужна только большая лопата для загребания денег.

Partisan ★★★★★
()
Ответ на: комментарий от slovazap

Тот же приснопамятный ragel позволяет писать структурированно, типа, условно

Тут не ragel, а c# (на линуксе тоже работает, чтоб споров не было)

Есть правда, кейс когда нужно парсить откровенный мусор (и скорее всего это кейс парсинга HTML, когда есть и незакрытые тэги и забытые кавычки и прочая, хотя я не верю что тэги можно разбивать по середине), и там скорее нужен особый подход, но в основе всё равно будут регулярки, а как из них собрать что-то осмысленное в плане структуры документа наверняка есть какие-нибудь paper’ы от гугла или мозиллы.

Это чистка результата конвертации из других форматов другими системами. В теории там вообще чистить ничего не надо, на практике откуда-то проникают html-теги, причем таки с разрывами. Что хуже - не только теги, но и entity и тоже с разрывами.

praseodim ★★★★★
() автор топика
Последнее исправление: praseodim (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.