Вы должны использовать парсер, если вас интересует лексическое или семантическое значение текста , когда шаблоны могут различаться. Парсеры, как правило, излишни, когда вы просто хотите сопоставить или заменить шаблоны символов , независимо от их функционального значения.
В вашем случае вас, похоже, интересует значение текста («функциональные компоненты» кода), поэтому парсер будет лучшим выбором. Однако парсеры могут использовать регулярные выражения внутри себя, поэтому их не следует рассматривать как взаимоисключающие.
Однако парсер не означает автоматически, что он должен быть сложным. Например, если вас интересуют блоки кода на языке C, вы можете просто проанализировать вложенные группы {и}. Этот синтаксический анализатор будет интересоваться только двумя токенами ('{' и '}') и блоками текста между ними.
Однако простого сравнения регулярных выражений здесь недостаточно из-за вложенной семантики. Возьмите следующий код:
void Foo(bool Bar)
{
if(Bar)
{
f();
}
else
{
g();
}
}
Парсер будет понимать общую область видимости Foo, а также каждую внутреннюю область видимости, содержащуюся в Foo (блоки if и else). По мере того, как он встречает каждый знак «{», он «понимает» их значение. Простой поиск, однако, не понимает смысла текста и может интерпретировать следующее как блок, который, конечно, мы знаем, неверен:
{
if(Bar)
{
f();
}