As everyone is saying, you cant do this with regex. And since Textmate has limited macro capability, you can't do it in Textmate.
What you need is a filter. And you can write one in any convenient language, like Python.
Here's one written in JavaScript; as you can see, they can be quite involved.
(Note that this has been tested, but not exhaustively.)
var BadScript = 'var foo : bar = "hi"; \n \
function foobar (){ \n \
//blah blah \n \
} \n \
var fubar:bar; \n \
var barfo:bar; \n \
var SomeObj = {X:3, Z:(9+17)}; \n \
Obj2 = {myfunc:function() {return 13;}};\n \
\n \
function imSoUgly(bReally, (1+4)){ \n \
if (bReally) { \n \
// Are too! \n \
} \n \
else { \n \
// Am not! \n \
} \n \
//Blah blah blah blah mr freeman \n \
} \n \
';
var GoodText = '';
var iRawLen = BadScript.length;
var bInFunction = false;
var iNumBraces = 0;
var iNumParentheses = 0;
var sFunctionState = 'clear'; //-- We need a state machine. More, below.
var sSuspectText = '';
var oKeyWord = { init:function (s) {this.name=s; this.len=s.length; this.J=0;},
sGet:function () {return this.name[this.J];},
reset:function () {this.J = 0;},
bIncr:function () {this.J += 1; if(this.J >= this.len) {this.J=0; return true;} else return false;}
};
oKeyWord.init ('function');
for (var K=0; K < iRawLen; K++)
{
var sChar = BadScript[K];
if (bInFunction)
{
if (sChar == '{')
{
iNumBraces++;
}
else if (sChar == '}')
{
iNumBraces--;
if (iNumBraces == 0)
{
sFunctionState = 'clear';
bInFunction = false;
}
}
continue;
}
var bInvalidFuncDeclaration = false;
sSuspectText += sChar;
switch (sFunctionState)
{
/*--- Our actions vary depending on one of 7 main states.
They are (in sequence):
'clear'
'in function tag'
'in whitespace, post tag'
'in function name'
'in whitespace, post name'
'in parentheses'
'in whitespace, post parentheses'
*/
case 'clear':
if (sChar == oKeyWord.sGet() )
{
sFunctionState = 'in function tag';
sSuspectText = sChar;
if (oKeyWord.bIncr() )
{
//--- Keyword was only 1 char long.
sFunctionState = 'in whitespace, post tag';
}
}
else
GoodText += sChar;
break;
case 'in function tag':
if (sChar == oKeyWord.sGet() )
{
if (oKeyWord.bIncr() )
{
//--- Reached the end of the keyword.
sFunctionState = 'in whitespace, post tag';
}
}
else
{
//--- We found a non-matching character before the keyword was completed.
oKeyWord.reset();
bInvalidFuncDeclaration = true;
}
break;
case 'in whitespace, post tag':
if (!/\s/.test (sChar) ) //-- Is not whitespace?
{
if (/\w/.test (sChar) ) //-- Legal name-char.
{
sFunctionState = 'in function name';
}
else if (sChar == '(')
{
//--- This is the case of an anonymous function.
sFunctionState = 'in parentheses';
iNumParentheses++;
}
else
{
bInvalidFuncDeclaration = true;
}
}
break;
case 'in function name':
if (!/\w/.test (sChar) ) //-- Not legal name-char?
{
if (/\s/.test (sChar) ) //-- Is whitespace?
{
sFunctionState = 'in whitespace, post name';
}
else if (sChar == '(')
{
sFunctionState = 'in parentheses';
iNumParentheses++;
}
else
{
bInvalidFuncDeclaration = true;
}
}
break;
case 'in whitespace, post name':
if (!/\s/.test (sChar) ) //-- Is not whitespace?
{
if (sChar == '(')
{
sFunctionState = 'in parentheses';
iNumParentheses++;
}
else
{
bInvalidFuncDeclaration = true;
}
}
break;
case 'in parentheses':
if (sChar == '(')
{
iNumParentheses++;
}
else if (sChar == ')')
{
iNumParentheses--;
if (iNumParentheses == 0)
{
sFunctionState = 'in whitespace, post parentheses';
bInFunction = false;
}
}
break;
case 'in whitespace, post parentheses':
if (!/\s/.test (sChar) ) //-- Is not whitespace?
{
if (sChar == '{')
{
sFunctionState = 'clear';
sSuspectText = '';
bInFunction = true;
iNumBraces++;
}
else
{
bInvalidFuncDeclaration = true;
}
}
break;
default:
throw new Error ('Undefined sFunctionState: "' + sFunctionState + '"');
break;
}
if (bInvalidFuncDeclaration)
{
GoodText += sSuspectText;
sFunctionState = 'clear';
sSuspectText = '';
bInFunction = false;
}
}
console.log (GoodText); //-- Use alert() if not Firebug.
if (iNumBraces) throw new Error ('Mismatched Braces. ' + iNumBraces + ' left over.');
if (iNumParentheses) throw new Error ('Mismatched Parentheses. ' + iNumParentheses + ' left over.');