Поскольку вы приняли мой (неправильный) ответ в другой теме, я чувствую, что я как бы обязан опубликовать надлежащее решение. Это не будет быстрым и коротким, но, надеюсь, немного помогает.
Ниже описано, как я буду писать парсер, основанный на регулярном выражении, для c-подобного языка, если понадобится.
<script>
/*
Let's start with this simple utility function. It's a
kind of stubborn version of String.replace() - it
checks the string over and over again, until nothing
more can be replaced
*/
function replaceAll(str, regexp, repl) {
str = str.toString();
while(str.match(regexp))
str = str.replace(regexp, repl);
return str;
}
/*
Next, we need a function that removes specific
constructs from the text and replaces them with
special "markers", which are "invisible" for further
processing. The matches are collected in a buffer so
that they can be restored later.
*/
function isolate(type, str, regexp, buf) {
return replaceAll(str, regexp, function($0) {
buf.push($0);
return "<<" + type + (buf.length - 1) + ">>";
});
}
/*
The following restores "isolated" strings from the
buffer:
*/
function restore(str, buf) {
return replaceAll(str, /<<[a-z]+(\d+)>>/g, function($0, $1) {
return buf[parseInt($1)];
});
}
/*
Write down the grammar. Javascript regexps are
notoriously hard to read (there is no "comment"
option like in perl), therefore let's use more
readable format with spacing and substitution
variables. Note that "$string" and "$block" rules are
actually "isolate()" markers.
*/
var grammar = {
$nothing: "",
$space: "\\s",
$access: "public $space+ | private $space+ | $nothing",
$ident: "[a-z_]\\w*",
$args: "[^()]*",
$string: "<<string [0-9]+>>",
$block: "<<block [0-9]+>>",
$fun: "($access) function $space* ($ident) $space* \\(($args) \\) $space* ($block)"
}
/*
This compiles the grammar to pure regexps - one for
each grammar rule:
*/
function compile(grammar) {
var re = {};
for(var p in grammar)
re[p] = new RegExp(
replaceAll(grammar[p], /\$\w+/g,
function($0) { return grammar[$0] }).
replace(/\s+/g, ""),
"gi");
return re;
}
/*
Let's put everything together
*/
function findFunctions(code, callback) {
var buf = [];
// isolate strings
code = isolate("string", code, /"(\\.|[^\"])*"/g, buf);
// isolate blocks in curly brackets {...}
code = isolate("block", code, /{[^{}]*}/g, buf);
// compile our grammar
var re = compile(grammar);
// and perform an action for each function we can find
code.replace(re.$fun, function() {
var p = [];
for(var i = 1; i < arguments.length; i++)
p.push(restore(arguments[i], buf));
return callback.apply(this, p)
});
}
</script>
Теперь мы готовы к испытанию. Наш парсер должен иметь возможность иметь дело с экранированными строками и произвольными вложенными блоками.
<code>
public function blah(arg1, arg2) {
if("some string" == "public function") {
callAnother("{hello}")
while(something) {
alert("escaped \" string");
}
}
}
function yetAnother() { alert("blah") }
</code>
<script>
window.onload = function() {
var code = document.getElementsByTagName("code")[0].innerHTML;
findFunctions(code, function(access, name, args, body) {
document.write(
"<br>" +
"<br> access= " + access +
"<br> name= " + name +
"<br> args= " + args +
"<br> body= " + body
)
});
}
</script>
Вы быстро: O – 2010-04-06 23:22:53
Будьте осторожны с решениями, говорящими вам использовать '(. *?)'. @outis имеет более подробную информацию об этом. –