1

Using javascript, im trying to make a node.js module to parse predicate logic statements. I've been working on this regex for a bit and I just can't get it to behave the way i want

1.     /\(((?:[^{}]*\([^{}]*\))*[^{}]*?)\)/
2.    .replace(/\)((?:[^{}]*\)[^{}]*\))*[^{}]*?)\(/,'):::(')

the latter works fine on things like (a&s&d&a&s&d)->(a&s&(d)&s|(d)) but i just switched the delimiters... what I'm trying to do is change a statement like

((r|a)&(s|r))&(~r)->(r|(q&r))->q

into

1->2->q

I can certainly write a procedural function to do it, that would be a fine solution. But Im really stuck on this.

The only real specification is the regex needs to respect the outermost parenthesis the most, and be able to replace separate ones.

Aage Torleif
  • 1,907
  • 1
  • 20
  • 37
  • 6
    This is not what regex are intended for. Looks like you are trying to parse an expression. Check: [When you should NOT use Regular Expressions?](http://programmers.stackexchange.com/questions/113237/when-you-should-not-use-regular-expressions), and [this](http://stackoverflow.com/questions/357814/when-is-it-best-to-use-regular-expressions-over-basic-string-spliting-substring) – thepirat000 Apr 05 '14 at 02:37
  • 2
    javascript regex engine doesn't have the necessary features (like recursion or a stack system) to deal with nested parenthesis (and to find the outermost parenthesis). If you want to do that you need to use a third party library (like xregexp) or to find an other approach. – Casimir et Hippolyte Apr 05 '14 at 02:42
  • Perhaps a [JavaScript parser generator](https://www.google.com/#q=javascript+parser+generator) would be useful in this situation. – Anderson Green Apr 05 '14 at 02:51

1 Answers1

0

Because this is not regex friendly I put togethor a couple of functions that do what you are looking for. The first matches parenthesis with depth:

function match_parens(code_to_test, level, opening, closing){
    var sub_match, matched;
    return code_to_test.replace(new RegExp('^([^'+opening+closing+']*(.))[\\s\\S]*$'), function(full_match, matched, $2, offset, original){
        if ($2 == opening){
            sub_match = match_parens(original.substr(offset+matched.length), level + 1, opening, closing);
            matched = matched + sub_match
        }
        else if (level > 1){
            sub_match = match_parens(original.substr(offset+matched.length), level - 1, opening, closing);
            matched += sub_match;
        }
        return matched;
    });
}

This function takes a string and returns everything up until the closing element.

The next function helps pulls a string passed to it apart, replacing all content in parenthesis with escalating numbers:

function pull_apart(testString){
    var count = 1,
            returnString = '',
            tempIndex = testString.indexOf('(');
    while (tempIndex !== -1){
        returnString += testString.substring(0,tempIndex)+count;
        count += 1;
        testString = testString.substring(testString.indexOf('(') + match_parens(testString.substr(tempIndex + 1), 1, '(', ')').length+1)
        tempIndex = testString.indexOf('(');
    }
    returnString += testString;
    return returnString;
}

Running pull_apart('((r|a)&(s|r))&(~r)->(r|(q&r))->q') returns "1&2->3->q", which is what you are looking for. While this is not entirely regex, it is utilized in the paren matching function up above. I'm not sure if this fits whatever use case you had in mind, but hopefully it helps.

wolffer-east
  • 1,069
  • 7
  • 14