PDA

View Full Version : Assigning to self



Trinithis
05-24-2007, 07:41 PM
RegExp.prototype.addFlags = function(flags) {
if(flags.match(/[^gim]/i)) return false;
var newFlags = flags.split("");
var temp = this.toString();
temp = temp.substr(1, temp.length-1).replace(/\/([^\/]*)$/, "")
var oldFlags = RegExp.$1;
for(var i=0; i<newFlags.length; i++) {
if(oldFlags.indexOf(newFlags[i])==-1) oldFlags += newFlags[i];
}
return new RegExp(temp, oldFlags);
//I want something like: this = new RegExp(temp, oldFlags); (If this worked that is...)
}

Where I have the bolded code is where I'm stuck. What I want to do is have the addFlags not return the new RegExp and instead change the variable object it is acting upon.


var pattern = /abc/i
pattern.addFlags("gm")
alert(pattern) //Currently outputs "/abc/i". I want it to output "/abc/gim"
pattern = pattern.addFlags("gm")
alert(pattern) //Outputs "/abc/gim"

Twey
05-24-2007, 08:31 PM
Flags seem to be read-only on RegExp instances, so I don't think you can. Getting the properties of the current object can be done a better way though:
if(typeof Array.prototype.indexOf !== "function")
Array.prototype.indexOf = function(val) {
for(var i = 0; i < this.length; ++i)
if(this[i] === val)
return i;
return -1;
};

Array.prototype.unique = function() {
var r = [], i;
for(i = 0; i < this.length; ++i)
if(r.indexOf(this[i]) === -1)
r.push(this[i]);
return r;
};

RegExp.prototype.addFlags = function(flags) {
var oldFlags = [], text = this.source;
for(var x in {'global' : false, 'ignoreCase' : false, 'multiline' : false})
if(this[x])
oldFlags.push(x[0]);
return (new RegExp(this.source, oldFlags.concat(flags.split("")).unique().join("")));
}

Trinithis
05-24-2007, 08:56 PM
Sorry, let me re-explain myself. I want to create a method that changes an object into a new object without using return.

What I don't want:
var x = new Object();
x = x.changeX();

What I want:
var x = new Object();
x.changeX();

Twey
05-24-2007, 09:03 PM
To repeat myself:
Flags seem to be read-only on RegExp instances, so I don't think you can.

mwinter
05-25-2007, 06:24 PM
Most built-in objects are immutable. The only exception that comes to mind is a Date instance.

Trinithis
05-25-2007, 07:08 PM
Actually, I just got it to work the way I wanted it to (by accident too :D. I read about the compile method, thinking it was like new RegExp, but it just timed faster with my tests, so I unwittingly kept it).


RegExp.prototype.addFlags = function(newFlags) {
var flags = "";
if(newFlags.indexOf("g")!=-1 || this.global) flags += "g";
if(newFlags.indexOf("i")!=-1 || this.ignoreCase) flags += "i";
if(newFlags.indexOf("m")!=-1 || this.multiline) flags += "m";
return this.compile(this.source, flags);
}
var r = /foo/;
r.addFlags("ig");
alert(r); // Outputs "/foo/gi" (or "/foo/ig" depending on the browser)
alert(r.addFlags("m")); // Outputs "/foo/gim"

Now I have to finish coding other RegExp methods.

jscheuer1
05-25-2007, 07:22 PM
Very nice! I wonder if those properties:

obj.ignoreCase
obj.multiline

of the RegExp object could be used as part of tests to see if the browser supports the i or m flags? I'm thinking probably. But, no real time to play with it right now.

Twey
05-25-2007, 07:23 PM
Ah! Well done, I shall bear this one in mind :)
I wonder if those properties:

obj.ignoreCase
obj.multiline

of the RegExp object could be used as part of tests to see if the browser supports the i or m flags?If the browser didn't support i or m, there'd be no reason for it to have ignoreCase or multiline. I suspect it would be reasonable to assume:
RegExp.supportsFlag = (function() {
var emptyRegex = new RegExp(),
possibleFlags = {
'g' : 'global',
'i' : 'ignoreCase',
'm' : 'multiline'
};
return function(flag) {
return !(typeof emptyRegex[possibleFlags[flag]] === "undefined");
};
})();

jscheuer1
05-25-2007, 07:41 PM
Yeah, I think that would work. I was looking for something more straightforward and hit it on the second shot (at least for supporting browsers):


if (typeof RegExp().ignoreCase=='boolean')
we can use the i flag here
else
do something to simulate case insensitivity here

The trick is to see if it works as expected in non-supporting browsers.

Trinithis
05-25-2007, 08:52 PM
You're going to have a hard time emulating flags that browsers do not support because JS does not support the regex inline mode "flags" (?g) (?i) (?m)... or at least both mine don't, and since they don't, I would suspect even older browsers would not.

If anything, if one were to use flags in the first place (setting aside all but the basic RegExp class) and a browser did not support it, then you are out of luck to begin with, before adding new methods. My case is that if you are worried about unsupporting browsers, then do not use flags to begin with.

BTW, are there even browsers that support regular expressions and not flags? Or if some only support 1 or 2 of them, then my code would return 'undefined' with let's say 'this.ignoreCase' and in the if-statement, it would act as 'false' and you have nothing to worry about anyway.

Twey
05-25-2007, 09:26 PM
You're going to have a hard time emulating flags that browsers do not support because JS does not support the regex inline mode "flags" (?g) (?i) (?m)... or at least both mine don't, and since they don't, I would suspect even older browsers would not.Not at all. There are workarounds for each:for /g, one would repeatedly match and trim the string up to and including the match; for /i, one would convert both strings to lowercase before attempting to match, or provide all possible options if the case must be preserved; and for /m, one can split the string on newlines and perform the match on each line separately.
BTW, are there even browsers that support regular expressions and not flags?Not in common use any more, no, as far as I'm aware.
Or if some only support 1 or 2 of them, then my code would return 'undefined' with let's say 'this.ignoreCase' and in the if-statement, it would act as 'false' and you have nothing to worry about anyway.Yes, certainly, we were just discussing a possibility for feature-detection rather than a potential problem with your code.

Trinithis
05-26-2007, 12:28 AM
multiline
This property reflects whether a search is to be carried out over multiple lines, returning true if it is, and false if not. Being a static property, you always use RegExp.multiline. When an event handler is called for a TEXTAREA form element, the browser sets the multiline property to true. Once the event handler has finished executing, it is reset to false, even if it was set at true before the event handler was called.

No need to worry about multiline I guess...

jscheuer1
05-26-2007, 05:03 AM
I'm not sure how exactly this fits in with all of this, but I've discovered that Opera doesn't like:


alert(typeof RegExp().multiline); //throws error

But, will go for:


var b=new RegExp();
alert(typeof b.multiline); //alerts boolean

and it is a supporting (of the multiline flag) browser. In NN4 which doesn't support the flag (but does support the i and g flags):


var b=new RegExp();
alert(typeof b.multiline); //alerts undefined


var b=new RegExp();
alert(typeof b.global); //alerts boolean

And, in NN4:


RegExp.prototype.addFlags = function(newFlags) {
var flags = "";
if(newFlags.indexOf("g")!=-1 || this.global) flags += "g";
if(newFlags.indexOf("i")!=-1 || this.ignoreCase) flags += "i";
if(newFlags.indexOf("m")!=-1 || this.multiline) flags += "m";
return this.compile(this.source, flags);
}
var r = new RegExp('foo');
r.addFlags("ig");
alert(r); // Outputs "/foo/gi"
alert(r.addFlags("m")); // Outputs "/foo/gi"

See red section, which is to be expected and, as suggested by the DevGuru excerpt, throws no error in the process.

Twey
05-26-2007, 05:59 PM
I'm not sure how exactly this fits in with all of this, but I've discovered that Opera doesn't like:

alert(typeof RegExp().multiline); //throws errorTry how it should be:
alert(typeof (new RegExp()).multiline);