2010-04-06 3 views
3

Я использую следующее регулярное выражение:Regex захватывает всю строку

(public|private +)?function +([a-zA-Z_$][0-9a-zA-Z_$]*) *\\(([0-9a-zA-Z_$, ]*)\\) *{(.*)} 

Чтобы соответствовать следующей строке:

public function messenger(text){ 
sendMsg(text); 
} 
private function sendMsg(text){ 
alert(text); 
} 

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

Я хотел, чтобы захватить обе функции, но захват: $ 1: «» $ 2: «мессенджер» $ 3: "текст" $ 4: "sendMsg (текст); } private function sendMsg (текст) {alert (текст); "

Кстати, я использую Javascript.

+0

Вы быстро: O – 2010-04-06 23:22:53

+0

Будьте осторожны с решениями, говорящими вам использовать '(. *?)'. @outis имеет более подробную информацию об этом. –

ответ

3

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

Ниже описано, как я буду писать парсер, основанный на регулярном выражении, для 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> 
1

Попробуйте изменить

(.*) 

в

(.*?) 
+0

Это не сработает, если в теле функции есть другой '}'. Например, что-то вроде 'if (foo) {doSomething; } 'в теле функции нарушит ваше решение. Вы не можете использовать регулярное выражение для анализа нерегулярного текста. –

3

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

/((?:(?:public|private)\s+)?)function\s+([a-zA-Z_$][\w$]*)\s*\(([\w$, ]*)\)\s*{(.*?)}/ 

\w соответствует словам и эквивалентен [a-zA-Z0-9_], но может использоваться в классах символов. Обратите внимание, что это не будет соответствовать функции с блоками в них, такие как:

function foo() { 
    for (p in this) { 
     ... 
    } 
} 

Это сложно невозможно сделать с регулярными выражениями, если они не поддерживают recursion (которые JS сделаем нет), поэтому вам нужно правильное синтаксический анализатор.

+0

Благодарим вас за то, что вы избегаете туннельного зрения, outis :) –

1

Изменить это последняя часть вашего регулярного выражения:

{(.*)} 

Для этого:

{(.*?)} 

Это делает его «не жадный», так что он не улавливает до последнего } в вход.

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

+0

Это не сработает, если в теле функции есть другой '}'. Например, что-то вроде 'if (foo) {doSomething; } 'в теле функции нарушит ваше решение. Вы не можете использовать регулярное выражение для анализа нерегулярного текста. –

+0

@smotchkkiss, это на самом деле своего рода круглый аргумент, потому что обычный язык по определению является тем, который могут анализировать регулярные выражения. В принципе, «вы не можете разобрать что-то, что вы не можете разобрать», разве вы не знаете. – user187291

Смежные вопросы