Поскольку ваш вопрос помечен как "perl", я предполагаю, что вы примете решение Perl.
Моей первой мыслью было использование модуля Text :: Balanced , в частности: extract_codeblock
(который на самом деле предназначен для Perl, но Perl и PHP достаточно похожи для анализа, чтобы получить приемлемые результаты) но это было не так просто, как я надеялся: extract_codeblock
только правильно вытащил выражение, если оно заключено в квадратные скобки (начинается с "{" или "(").
Что ж, с помощью этого модуля и написания моего собственного подкомпонента, объединяющего процедуры разбора токенов, я получил нечто, что внешне кажется работающим.
use Text::Balanced qw(extract_bracketed extract_quotelike);
sub extract_expression {
local $_ = shift;
my $parsed;
while(1) {
if(s&^(\s*)((?:(?!//|/\*|#)[^[{(\]),;'"'\s])+)&&) {
# normal characters (no delimiters, quotes or brackets, or comments)
$parsed .= "$1$2";
} elsif(/^\s*(?=['"'])/) {
# quotes
(my $token, $_) = extract_quotelike($_, '\'"');
defined $token or last;
$parsed .= $token;
} elsif(/^\s*(?=[\[\{\(])/) {
# brackets
(my $token, $_) = extract_bracketed($_, '[({\'"})]');
defined $token or last;
$parsed .= $token;
} elsif(s&^\s*(?://|\#).*\n?&& || s&^\s*/\*.*?\*/&&s) {
# comments
# ignore
} else {
# not recognized
# finished
last;
}
}
return $parsed, $_;
}
# demo
# complex line of PHP (borrowed from Drupal)
$_ = <<'PHP';
$translations[$lang] = $this->drupalCreateNode(array('type' => $source->type, 'language' => $lang, 'translation_source' => $source, 'status' => $source->status, 'promote' => $source->promote, 'uid' => $source->uid));
# etc
PHP
if(/->drupalCreateNode\(/) {
my $offset = $+[0]; # position right after opening paren
my($expression, $rest) = extract_expression(substr($_, $offset));
if(defined $expression) {
print <<"INFO";
parsed expression: $expression
rest: $rest
INFO
} else {
print "Failure to parse expression\n";
}
}
Ну, я подумал ... комментарии в PHP отличаются от комментариев в Perl, и внешне я обработал комментарии PHP, но, к сожалению, процедура не рекурсивна и только комментарии за пределами любые заключены в скобки выражения должным образом игнорируются. Внутренние комментарии могут запутать синтаксический анализатор (extract_bracketed
).