//---------------------------------------------------------------------------
// RegExp object for Flash5 ActionScript Ver1.01
// Author: Pavils Jurjans
// Email : pavils@mailbox.riga.lv
// Default source for this file can be found at:
// http://www.jurjans.lv/flash/RegExp.html
// and an interactive tester at http://www.jurjans.lv/flash/RegExp_test.html
//---------------------------------------------------------------------------
// This class is provided for flash community for free with a kind request
// to keep the copyright lines in AS file untouched. However, debugging and
// development of class takes much time limiting my opportunities to earn
// some income on other projects. To overcome this, I have set up an account
// with PayPal (http://www.paypal.com). Please, if you find my work valuable,
// especially if you use it in commercial projects, make a donation
// to pavils@mailbox.riga.lv of amount you feel is right. Please provide your
// E-mail address upon payment submission so I can enlist you in my upgrade newslist.
//---------------------------------------------------------------------------
/** Based on RegExp object for Flash5 ActionScript Ver1.01
*RegExp is defined in Javascript and Actionscript 3 but is missing in Actionscript 2 (see Actionscript 3 documentation).
*Test Regular Expressions at http://www.jurjans.lv/flash/RegExp_test.html.
*Read a nice summary of their use at http://www.websina.com/bugzero/kb/regexp.html
* Help Document Last Updated: Jan 11, 2010
*@author Pavils Jurjans and Joey Lott with additions by the CLIPS team
@email gpclarke@smcdsb.on.ca
@url http://www.jurjans.lv/flash/RegExp.html
*/
class edu.clips.util.RegExp {
public var const:String = null;
public var source:String = null;
public var global:Boolean = false;
public var ignoreCase:Boolean = false;
public var multiline:Boolean = false;
public var lastIndex:Number = null;
public static var _xrStatic:Number = null;
public var _xr:Number = null;
public static var _xp:Number = null;
public static var _xxa:Array = null;
public static var _xxlp:Number = null;
public var _xq:Number = null;
public var _xqc:Number = null;
public static var d:Number = null;
public static var _xiStatic:Number = null;
public var _xi:Number = 0;
public static var _xxlm:String = null;
public static var _xxlc:String = null;
public static var _xxrc:String = null;
public static var lastMatch:String = null;
public static var leftContext:String = null;
public static var rightContext:String = null;
public static var _xa:Array = new Array();
public static var lastParen:String = null;
public static var _xaStatic:Array = new Array();
public static var $1:String = null;
public static var $2:String = null;
public static var $3:String = null;
public static var $4:String = null;
public static var $5:String = null;
public static var $6:String = null;
public static var $7:String = null;
public static var $8:String = null;
public static var $9:String = null;
//this device sets up the String prototype functions immediately
private static var _setString:Boolean = RegExp.setStringMethods();
/**
* Instantiates a Regular Expression
* @usage import edu.clips.util.RegExp;
var thing = new RegExp(string, flags, mystery);
* @param string String defining the pattern
* @param flags some subset of "gim" where g indicates a global search, i a case-insensitive one and m a multi-line one
* @param mystery - I think this is used only internally by the class
* @example import edu.clips.util.RegExp;
var re = new RegExp("\\s+CLIPS","g");
*/
function RegExp() {
if (arguments[0] == null) {
} else {
const = "RegExp";
compile.apply(this, arguments);
}
}
/**Used to determine which version of the class is actually stored and used
*@returns (String) Details of the current version. */
public function getVersionInfo():String {
return "RegExp Version January 26, 2010";
}
public function invStr(sVal:String):String {
var s = sVal;
var l = length(s);
var j;
var c;
var r = "";
for (var i = 1; i<255; i++) {
c = chr(i);
j = 0;
while (j<=l && substring(s, 1+j++, 1) != c) {
}
if (j>l) {
r += c;
}
}
return s;
}
public function compile() {
this.source = arguments[0];
if (arguments.length>1) {
var flags = (arguments[1]+'').toLowerCase();
for (var i = 0; i type of match required: 0 = exact
1 = in char set
2 = not in char set
3 = paren
4 = ref to paren
7 = new "OR" section
9 = beginning of line
10 = end of line
q[n].s --> character or character set
q[n].a --> character has to repeat at least a times
q[n].b --> character has to repeat at most b times
*/
var re = this.source;
var ex;
var l = length(re);
var q = [];
var qc = 0;
var s;
var range = false;
var ca;
var cb;
var atEnd = false;
var char;
for (i=i; i=(s=chr(ca++))) {
thischar += s;
}
range = false;
} else {
if (s == "-" && length(thischar)>0) {
//Character range is being defined
range = true;
} else {
if (s == "\\") {
//Predefined char set may follow
s = substring(re, 1+i++, 1);
if (s == "d") {
thischar += "0123456789";
} else if (s == "D") {
thischar += invStr("0123456789");
} else if (s == "s") {
thischar += " \f\n\r\t\v";
} else if (s == "S") {
thischar += invStr(" \f\n\r\t\v");
} else if (s == "w") {
thischar += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
} else if (s == "W") {
thischar += invStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_");
} else if (s == "b") {
thischar += chr(8);
} else if (s == "\\") {
thischar += s;
}
} else {
thischar += s;
}
}
}
}
if (range) thischar += "-";
i--;
var nextchar = substring(re, i+2, 1);
} else if (thischar == "|") {
//OR section
if (atEnd) {
q[qc].t = 10;
q[qc].a = 1;
q[qc].b = 1;
qc++;
q[qc] = new Object();
atEnd = false;
}
q[qc].t = 7;
q[qc].a = 1;
q[qc].b = 1;
qc++;
continue;
} else if (thischar == ".") {
q[qc].t = 2;
thischar = "\n";
} else if (thischar == "*" || thischar == "?" || thischar == "+") {
continue;
}
} else {
if (thischar>="1" && thischar<="9") {
q[qc].t = 4;
} else if (thischar == "b") {
q[qc].t = 1;
thischar = "--wb--";
} else if (thischar == "B") {
q[qc].t = 2;
thischar = "--wb--";
} else if (thischar == "d") {
q[qc].t = 1;
thischar = "0123456789";
} else if (thischar == "D") {
q[qc].t = 2;
thischar = "0123456789";
} else if (thischar == "s") {
q[qc].t = 1;
thischar = " \f\n\r\t\v";
} else if (thischar == "S") {
q[qc].t = 2;
thischar = " \f\n\r\t\v";
} else if (thischar == "w") {
q[qc].t = 1;
thischar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
} else if (thischar == "W") {
q[qc].t = 2;
thischar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
}
}
//Counting metacharacters
if (nextchar == "*") {
q[qc].s = thischar;
qc++;
i++;
} else if (nextchar == "?") {
q[qc].s = thischar;
q[qc].b = 1;
qc++;
i++;
} else if (nextchar == "+") {
q[qc].s = thischar;
q[qc].a = 1;
qc++;
i++;
} else if (nextchar == "{") {
var comma = false;
var rangeA = 0;
range = "";
i++;
while (i+1(String) The string to be searched
*@returns Boolean indicating whether the pattern was found
*@example nameof = "StandardStart27_mc"
var re = new RegExp("Start","g");
trace("Does the string include 'Start'? "+re.test(nameof)); //outputs true*/
public function test() {
if (RegExp._xp++ == 0) {
RegExp._xxa = [];
//Temp array for storing paren matches
RegExp._xxlp = 0;
//Last paren
}
// q[n].c --> count of matches
// q[n].i --> index within the string
var str = arguments[0]+'';
var re;
var q = this._xq;
var qc = this._xqc;
var qb;
var c;
var cl;
var ct;
var s;
var l = length(str);
var ix = this.global ? this.lastIndex : 0;
var ix_ = ix;
var str_ = str;
if (this.ignoreCase) {
str = str.toLowerCase();
}
var r = new Object();
r.i = -1;
var i = -1;
while (i=0 && ix>=r.i) {
//There is already better match, so quit searching
break;
}
if (q[i].c == -10) {
if (RegExp.d) {
trace("Lookup #"+i+" at index "+ix+" for \\\\\\\\\\\\\\\\'"+q[i].s+"\\\\\\\\\\\\\\\\' type "+q[i].t);
}
//Count the # of matches
var m = 0;
q[i].i = ix;
if (q[i].t == 0) {
//Exact match
c = this.ignoreCase ? q[i].s.toLowerCase() : q[i].s;
while (m0 && ix0 && ix0) {
ix += cl;
m++;
q[i].ix[m] = ix;
} else {
m = q[i].a;
q[i].ix[m-1] = ix;
break;
}
}
if (m == 0) {
RegExp._xxlm = "";
}
if (re._xr>RegExp._xxlp) {
RegExp._xxlp = re._xr;
}
RegExp._xxa[Number(re._xr)] = RegExp._xxlm;
} else if (q[i].t == 4) {
//Back reference to paren
if (RegExp._xp>=(c=Number(q[i].s))) {
c = RegExp._xxa[c];
c = this.ignoreCase ? c.toLowerCase() : c;
cl = length(c);
q[i].ix = [];
q[i].ix[m] = ix;
if (cl>0) {
while (mqb) {
//Retreat back and decrease # of assumed matches
i--;
q[i].c--;
if (q[i].c>=0) {
ix = (q[i].t == 3 || q[i].t == 4) ? q[i].ix[q[i].c] : (q[i].i+q[i].c);
}
if (RegExp.d) {
trace("Retreat to #"+i+" c="+q[i].c+" index="+ix);
}
} else {
if (RegExp._xp>1) {
//If this is a paren, failing to find first match is fatal
break;
}
if (atStart) {
//Match must be at the start of string/line
if (this.multiline) {
//Jump to the beginning of the next line
while (ix<=l) {
s = substring(str, 1+ix++, 1);
if (s == "\\\\\\\\\\\\\\\\n" || s == "\\\\\\\\\\\\\\\\r") {
break;
}
}
q[i].c = -10;
} else {
//No match
break;
}
} else {
//Start a new search from next position
ix++;
q[i].c = -10;
}
}
} else {
if (RegExp.d) {
trace(" enough matches!");
}
//# of matches ok, proceed to next
i++;
if (i == qc || q[i].t == 7) {
if (RegExp.d) {
trace("Saving better result: r.i = q["+qb+"].i = "+q[qb].i);
}
r.i = q[qb].i;
r.li = ix;
break;
} else {
q[i].c = -10;
}
}
}
}
while (i(String) The string to be pattern-matched
*@returns Object with properties index (the position), input (the string) and 0 (the matched character(s))
*Note: previous operations with the RegExp object may affect the last Index being considered and hence the results. Multiple calls to exec are necessary to get all the matches.
*@example p2 = new RegExp("\\d+","g");
next_string = "I have 23 ways to list 5 objects on 217 pieces of paper";
var results1:Object = p2.exec(next_string);
while (results1 != null)
{
for (var prop in results1){
trace(" * "+prop+" : "+results1[prop]);
}
results1 = p2.exec(next_string);
}
*/
public function exec() {
var str = arguments[0]+'';
if (str == '') {
return false;
}
var t = this.test(str);
if (t) {
var ra = new Array();
ra.index = this._xi;
ra.input = str;
ra[0] = RegExp.lastMatch;
var l = RegExp._xaStatic.length;
for (var i = 1; i
Use the "g" flag to repeat the process over and over.
Added to String.prototype so that it can be used with any string.
Changed on January 26, 2010 to return a string - not sure how that will affect multiple calls with the "g" flag
*@usage string.match(re)
*@param string (String) The string to be pattern-matched
*@returns Array with every matched set of characters
*@example nameof = "StandardStart27_mc";
p2 = new RegExp("\\d+","g");
trace("The digits are " + nameof.match(p2)[0]); //output 27
*/
//public function match(re:RegExp):Array{
String.prototype.match = function() {
if (typeof (arguments[0]) != "object") {
return null;
}
if (arguments[0].const != "RegExp") {
trace("Warning - match not sent a RegExp");
return null;
}
var re = arguments[0];
var s = this.valueOf();
var ip = 0;
var rc = 0;
if (re.global) {
re.lastIndex = 0;
while (re.test(s)) {
if (rc == 0) {
var ra = new Array();
}
ra[rc++] = RegExp.lastMatch;
ip = re.lastIndex;
}
re.lastIndex = ip;
} else {
var ra = re.exec(s);
rc++;
}
return (rc == 0) ? null : ra;
};
/**Replace the characters that match the pattern defined by the regular expression with another string.
*or Replace the given substring with another one (Based on a idea of Davide Beltrame (Broly))
*found on http://www.sephiroth.it/proto_detail.php?id=16
Added to String.prototype so that it can be used with any string.
*@usage string.replace(re, new_string);
*@usage string.replace(found_string, new_string);
*@param re (RegExp) The Regular Expression with the pattern to be matched
*@param found_string (String) The string to be matched
*@param new_string (String) The string to use in the replacement
*@returns String with replacement(s) made.
*@example test_txt = " swf Missippi River ";
p1 = new RegExp("\\s+","g");
trace(test_txt.replace(p1,"*")); //output '*swf*Missippi*River*'
*@example test = ".swflib/actions/test.swf is a .swf";
* trace(test+", "+test.replace('.swf', '')); //.swflib/actions/test.swf is a .swf, lib/actions/test is a
*/
//public function replace(re:RegExp, new_string:String):String{
String.prototype.replace = function() {
if (typeof (arguments[0]) != "object") {
trace("Warning - replace not sent an Object");
//return null;
}
if (arguments[0].const != "RegExp") {
//definition when the first argument is a String
var arg_search, arg_replace, position;
var endText, preText, newText;
arg_search = arguments[0];
arg_replace = arguments[1];
if (arg_search.length == 1) {
return this.split(arg_search).join(arg_replace);
}
position = this.indexOf(arg_search);
if (position == -1) {
return this;
}
endText = this;
newText = "";
do {
position = endText.indexOf(arg_search);
preText = endText.substring(0, position);
endText = endText.substring(position+arg_search.length);
newText += preText+arg_replace;
} while (endText.indexOf(arg_search) != -1);
newText += endText;
trace("replace returning a result based on a string object");
return newText;
}
var re = arguments[0];
var rs = arguments[1]+'';
var s = this;
var r = "";
re.lastIndex = 0;
if (re.global) {
var ip = 0;
var ix = 0;
while (re.test(s)) {
//Replace backreferences in rs
var i = 0;
var l = length(rs);
var c = "";
var pc = "";
var nrs = "";
while (i9) {
nrs += "$"+c;
} else {
nrs += RegExp._xaStatic[Number(c)];
}
} else {
nrs += c;
}
pc = c;
}
r += substring(s, ix+1, re._xi-ix)+nrs;
ix = re._xi+length(RegExp.lastMatch);
ip = re.lastIndex;
}
re.lastIndex = ip;
} else {
if (re.test(s)) {
r += RegExp.leftContext+rs;
}
}
r += re.lastIndex == 0 ? s : RegExp.rightContext;
return r;
};
/**Trim whitespace from the beginning of a string.
*Added to the class, informed by http://www.somacon.com/p355.php
*Added to String.prototype so that it can be used with any string.
*@usage string.ltrim();
*@returns trimmed String
*@example test_txt = " swf Missippi River ";
trace(test_txt.ltrim()); //output 'swf Missippi River '
*/
//public function ltrim():String{
String.prototype.ltrim = function() {
var re = new RegExp("^\\s+");
return this.replace(re,"");
}
/**Trim whitespace from the end of a string.
*Added to the class, informed by http://www.somacon.com/p355.php
*Added to String.prototype so that it can be used with any string.
*@usage string.rtrim();
*@returns trimmed String
*@example test_txt = " swf Missippi River ";
trace(test_txt.rtrim()); //output ' swf Missippi River'
*/
//public function rtrim():String{
String.prototype.rtrim = function() {
var re = new RegExp("\\s+$")
return this.replace(re,"");
}
/**Trim whitespace from the beginning and end of a string.
*Added to the class by the CLIPS team
*Added to String.prototype so that it can be used with any string.
*@usage string.trim();
*@returns trimmed String
*@example test_txt = " swf Missippi River ";
trace(test_txt.trim()); //output 'swf Missippi River'
*/
//public function trim():String{
String.prototype.trim = function() {
//This device is used since the RegExp for whitespace at both ends didn't seem to work.
return this.rtrim().ltrim();
}
/**Tests for a match in a string.
*Added to String.prototype so that it can be used with any string.
*@usage string.search(re);
*@returns the index of the match, or -1 if the search fails.
*@example test_txt = "Therrrre Grrrrrrrrrreat";
re = new RegExp("r+e","g");
trace(test_txt.search(re)); //output 3
*@see test
*/
//public function search(re:RegExp):String{
String.prototype.search = function() {
if (typeof (arguments[0]) != "object") {
return null;
}
if (arguments[0].const != "RegExp") {
trace("Warning - search not sent a RegExp");
return null;
}
var re = arguments[0];
var s = this;
re.lastIndex = 0;
var t = re.test(s);
return t ? re._xi : -1;
};
String.prototype.old_split = String.prototype.split;
/**Adds the ability to split a string based on a RegExp.
*Added to String.prototype so that it can be used with any string.
*@usage string.split(re);
*@usage string.split(string_delimiter, limit);
*@param re the RegExp
*@param string_delimiter the simple string to delimit by
*@param limit the number of items to place in the array
*@returns an Array of substrings
*@example test_txt = "Therrrre Grrrrrrrrrreat";
re = new RegExp("r+e","g");
trace(test_txt.split(re)); //output [The, G,at]
trace(test_txt.split("r"); //output [The,,,,e G,,,,,,,,,,eat]
*/
//public function split(re:RegExp):String{
String.prototype.split = function() {
if (typeof (arguments[0]) == "object" && arguments[0].const == "RegExp") {
var re = arguments[0];
var lm = arguments[1] == null ? 9999 : Number(arguments[1]);
if (isNaN(lm)) {
lm = 9999;
}
var s = this;
var ra = new Array();
var rc = 0;
var gs = re.global;
re.global = true;
re.lastIndex = 0;
var ip = 0;
var ipp = 0;
var ix = 0;
while (rc0) {
ra[rc++] = RegExp.rightContext;
}
}
re.global = gs;
return ra;
} else {
return this.old_split(arguments[0], arguments[1]);
}
};
return true;
}
}