Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #21077 > unrolled thread
| Started by | brettz9@gmail.com |
|---|---|
| First post | 2013-08-28 07:51 -0700 |
| Last post | 2013-09-01 15:25 +0200 |
| Articles | 6 — 3 participants |
Back to article view | Back to comp.lang.javascript
Recommendation for new RegExp (Array-extra-like) methods brettz9@gmail.com - 2013-08-28 07:51 -0700
Re: Recommendation for new RegExp (Array-extra-like) methods Andreas Bergmaier <andber93@web.de> - 2013-08-28 17:16 +0200
Re: Recommendation for new RegExp (Array-extra-like) methods brettz9@gmail.com - 2013-08-28 08:21 -0700
Recommendation for array-like methods on Iterator; Was Re: Recommendation for new RegExp (Array-extra-like) methods brettz9@gmail.com - 2013-08-28 16:30 -0700
Re: Recommendation for new RegExp (Array-extra-like) methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-08-30 16:00 +0200
Re: Recommendation for new RegExp (Array-extra-like) methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-09-01 15:25 +0200
| From | brettz9@gmail.com |
|---|---|
| Date | 2013-08-28 07:51 -0700 |
| Subject | Recommendation for new RegExp (Array-extra-like) methods |
| Message-ID | <ac07e89f-90ee-4b6d-a524-5adfadd0cb94@googlegroups.com> |
Hi,
I'd be interested to see a way to get over the requirement for writing patterns like this:
while ((matches = regex.exec(str)) !== null) {
I envisioned solving this through an API that could work like this:
(/^(.*?): (.*)$/m).forEach('key1: val1\nkey2: key2', function (key, val, i, n0) {
document.writeln('key is ' + key + ', value is ' + val + ', and the iteration count is ' + i + '<br>');
});
I have this and other such Array-extra-like methods added to RegExp.prototype at https://gist.github.com/brettz9/6366721 (live at http://brett-zamir.me/tests/proposal-regexp-extensions.html ) as a kind of proof-of-concept.
Might something like this that makes global exec iteration more functional be possible as a new addition to the next ECMAScript standard?
[toc] | [next] | [standalone]
| From | Andreas Bergmaier <andber93@web.de> |
|---|---|
| Date | 2013-08-28 17:16 +0200 |
| Message-ID | <kvl485$rse$1@news.albasani.net> |
| In reply to | #21077 |
brettz9@gmail.com schrieb:
> I have Array-extra-like methods added to RegExp.prototype at
> https://gist.github.com/brettz9/6366721
I don't see much reason to do so. The method names imply that you are
iterating over the regex object, but that's not what you're doing.
To me it would make much more sense to have a simple method like
RegExp.prototype.execAll = function execAll(str) {
var res = [],
regex = this.global ? this : new RegExp(this, "g"),
matches;
while (matches = regex.exec(str))
res.push(matches);
return res;
};
String.prototype.matchAll = function(reg) { return reg.execAll(this); };
that you can call on a regex and then use arbitrary (actual) Array
methods on the result.
Greetings,
Bergi
[toc] | [prev] | [next] | [standalone]
| From | brettz9@gmail.com |
|---|---|
| Date | 2013-08-28 08:21 -0700 |
| Message-ID | <4e7f201e-b614-4d58-a48e-0e0a11560aba@googlegroups.com> |
| In reply to | #21078 |
On Wednesday, August 28, 2013 11:16:25 PM UTC+8, Andreas Bergmaier wrote:
> brettz9@gmail.com schrieb:
>
>
>
> > I have Array-extra-like methods added to RegExp.prototype at
>
> > https://gist.github.com/brettz9/6366721
>
>
>
> I don't see much reason to do so. The method names imply that you are
>
> iterating over the regex object, but that's not what you're doing.
>
>
>
> To me it would make much more sense to have a simple method like
>
>
>
> RegExp.prototype.execAll = function execAll(str) {
>
> var res = [],
>
> regex = this.global ? this : new RegExp(this, "g"),
>
> matches;
>
> while (matches = regex.exec(str))
>
> res.push(matches);
>
> return res;
>
> };
>
> String.prototype.matchAll = function(reg) { return reg.execAll(this); };
>
>
>
> that you can call on a regex and then use arbitrary (actual) Array
>
> methods on the result.
>
>
>
> Greetings,
>
> Bergi
I see your point on the semantics of it, but with your approach it is not possible to abandon the iteration early--for example, as with "some()". Still, even having that limited functionality built in would be better than nothing.
[toc] | [prev] | [next] | [standalone]
| From | brettz9@gmail.com |
|---|---|
| Date | 2013-08-28 16:30 -0700 |
| Subject | Recommendation for array-like methods on Iterator; Was Re: Recommendation for new RegExp (Array-extra-like) methods |
| Message-ID | <abfb1b68-f762-46e2-9e27-06584069c788@googlegroups.com> |
| In reply to | #21080 |
On Wednesday, August 28, 2013 11:21:55 PM UTC+8, bre...@gmail.com wrote:
> On Wednesday, August 28, 2013 11:16:25 PM UTC+8, Andreas Bergmaier wrote:
>
> > brettz9@gmail.com schrieb:
>
> >
>
> >
>
> >
>
> > > I have Array-extra-like methods added to RegExp.prototype at
>
> >
>
> > > https://gist.github.com/brettz9/6366721
>
> >
>
> >
>
> >
>
> > I don't see much reason to do so. The method names imply that you are
>
> >
>
> > iterating over the regex object, but that's not what you're doing.
>
> >
>
> >
>
> >
>
> > To me it would make much more sense to have a simple method like
>
> >
>
> >
>
> >
>
> > RegExp.prototype.execAll = function execAll(str) {
>
> >
>
> > var res = [],
>
> >
>
> > regex = this.global ? this : new RegExp(this, "g"),
>
> >
>
> > matches;
>
> >
>
> > while (matches = regex.exec(str))
>
> >
>
> > res.push(matches);
>
> >
>
> > return res;
>
> >
>
> > };
>
> >
>
> > String.prototype.matchAll = function(reg) { return reg.execAll(this); };
>
> >
>
> >
>
> >
>
> > that you can call on a regex and then use arbitrary (actual) Array
>
> >
>
> > methods on the result.
>
> >
>
> >
>
> >
>
> > Greetings,
>
> >
>
> > Bergi
>
>
>
> I see your point on the semantics of it, but with your approach it is not possible to abandon the iteration early--for example, as with "some()". Still, even having that limited functionality built in would be better than nothing.
After considering the points you raised, I realized that I was really looking for the general ability to iterate in a functional manner (i.e., something like a "Object.forEach" but available on all iterators--or perhaps a subclass of iterators designated for those which can be treated like arrays).
var obj = {'0': '0', a:3, b: 'b'};
Iterator(obj).some(function (key, val, i) {
return key === val;
}); // true
Iterator(obj, true).some(function (key, i) {
return parseInt(key, 10) === i;
}); // true
And then, the functional wrapping of the...
while ((matches = regex.exec(str)) !== null) {
...ugliness could be achieved through the likes of a class method (again, my hope would be built-in):
RegExp.iterator(/^(.*?): (.*)$/gm, 'key1: val1\nkey2: key2').some(function (n0, key, val, i) {
return key === val;
}); // true
A JavaScript 1.8 (Firefox) concept demo: https://gist.github.com/brettz9/6372591 (live at http://brett-zamir.me/tests/proposal-iterator-methods.html )
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-08-30 16:00 +0200 |
| Message-ID | <3573991.qt74eh6WeI@PointedEars.de> |
| In reply to | #21077 |
brettz9@gmail.com wrote:
> I'd be interested to see a way to get over the requirement for writing
> patterns like this:
>
> while ((matches = regex.exec(str)) !== null) {
Why, and what is the use-case for your proposal?
> I envisioned solving this through an API that could work like this:
>
> (/^(.*?): (.*)$/m).forEach('key1: val1\nkey2: key2',
Whereas your RegExp.prototype.forEach() is:
| function _mixinRegex (regex, newFlags, newLastIndex) {
| newLastIndex = newLastIndex === undefined ? regex.lastIndex :
| newLastIndex;
“undefined” is not read-only in less recent implementations. Use the
“typeof” operator instead.
| newFlags = newFlags || '';
See below.
| regex = new RegExp(
| regex.source,
| (newFlags.indexOf('g') > -1 ? 'g' : regex.global ? 'g' : '') +
| (newFlags.indexOf('i') > -1 ? 'i' : regex.ignoreCase ? 'i'
| : '') +
| (newFlags.indexOf('m') > -1 ? 'm' : regex.multiline ? 'm'
| : '') +
| (newFlags.indexOf('y') > -1 ? 'y' : regex.sticky ? 'y' :
| '') // Non-standard but harmless if already being used
| );
| regex.lastIndex = newLastIndex;
| return regex;
| }
|
| RegExp.prototype.forEach = function (str, cb, thisObj) {
| var matches, n0, i = 0, regex = _mixinRegex(this, 'g');
| thisObj = thisObj || null;
Should be
if (typeof thisObj == "undefined")
{
thisObj = null;
}
| while ((matches = regex.exec(str)) !== null) {
| n0 = matches.splice(0, 1);
| cb.apply(thisObj, matches.concat(i++, n0));
| }
| };
As you are wrapping RegExp.prototype.exec(), you have to create a new RegExp
instance with _mixinRegx() in order to prevent this from running forever.
Because you cannot rely on the global modifier being set on the “this”
value, and you cannot set it afterwards (the “global” property is read-only,
a poor design choice in ES, IMHO). So on *each* call of your
RegExp.prototype.forEach() there is yet another object created, and all the
property fixes required then are performed, needlessly.
| function (key, val, i, n0) {
| document.writeln('key is ' + key + ', value is ' + val + ', and the
| iteration count is ' + i + '<br>');
| });
|
| I have this and other such Array-extra-like methods added to
| RegExp.prototype at https://gist.github.com/brettz9/6366721 (live at
| http://brett-zamir.me/tests/proposal-regexp-extensions.html ) as a kind of
| proof-of-concept.
This is _not_ the Web. It would have been better had you also posted some
code here.
> Might something like this that makes global exec iteration more functional
> be possible as a new addition to the next ECMAScript standard?
Possible, yes; likely, no. Consider that function calls are among the most
expensive constructs, and there is no reason why a second RegExp instance is
necessary here other than syntactic sugar. [I think introducing
Array.prototype.forEach() was a mistake to begin with. It would have been
better to adopt E4X's “for each”. But when you have John Resig of all
people as “JavaScript Evangelist” at Mozilla, what do you expect? jQuery is
strewn with inefficiencies like this, and so is all jQuery-based code.]
You might instead find my jsx.regexp.RegExp useful, which among other
features allows you to name subpatterns and access by that name the
corresponding matches:
/* ?<Perl> style; also supports ?'Perl' style and ?P<ython> style */
var regex = new jsx.regexp.RegExp("^(?<first>.+?): (?<second>.+)$", "mg"),
str = "key1: val1\nkey2: key2",
match;
while ((match = regex.exec(str)))
{
console.log(match.groups["first"], match.groups["second"]);
console.log(match[1], match[2]);
}
“regex” holds an augmented RegExp instance then, whose inherited exec()
method has been overridden in the instance to return an augmented array-like
object if necessary (otherwise just the inherited method is called, and its
return value returned):
/**
* @function
*/
exec: (function () {
var rx2;
/**
* @param {string} s
* @param {jsx.regexp.RegExp} rx
* Instance to be tested
* @return {boolean}
* <code>true</code> if <var>rx</var> has been constructed
* using this constructor, <code>false</code> otherwise.
*/
function _exec (s, rx)
{
/* NOTE: Use passed expression only when called statically */
if (_getClass(this) == "RegExp")
{
rx = this;
}
rx._realExec = (rx._oldExec || rx.exec);
var matches = rx._realExec(s);
if (matches && _RegExp2.isInstance(rx))
{
matches.groups = _getDataObject();
if (rx.unicodeMode && !rx2)
{
rx2 = new _RegExp2("^\\W+", "u");
}
for (var i = 0, len = matches.length; i < len; ++i)
{
/* Trim leading \b matches */
var patternGroup = rx._patternGroups[i];
if (rx.unicodeMode
&& patternGroup
&& patternGroup.match(
/^(\((\?P?(<([^>]+)>|'([^']+)'))?)*\\b/))
{
matches[i] = matches[i].replace(rx2, "");
}
matches.groups[rx.groups[i] || i] = matches[i];
}
}
return matches;
}
return _exec;
}()),
See <http://PointedEars.de/scripts/test/regexp> for more.
--
PointedEars
Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-09-01 15:25 +0200 |
| Message-ID | <1458401.hGLh0OfnHy@PointedEars.de> |
| In reply to | #21115 |
Thomas 'PointedEars' Lahn wrote:
> You might instead find my jsx.regexp.RegExp useful, which among other
> features allows you to name subpatterns and access by that name the
> corresponding matches:
>
> /* ?<Perl> style; also supports ?'Perl' style and ?P<ython> style */
> var regex = new jsx.regexp.RegExp("^(?<first>.+?): (?<second>.+)$",
> "mg"),
> str = "key1: val1\nkey2: key2",
> match;
>
> while ((match = regex.exec(str)))
> {
> console.log(match.groups["first"], match.groups["second"]);
> console.log(match[1], match[2]);
> }
>
> “regex” holds an augmented RegExp instance then, whose inherited exec()
> method has been overridden in the instance to return an augmented
> array-like object if necessary (otherwise just the inherited method is
> called, and its return value returned):
>
> /**
> * @function
> */
> exec: (function () {
> var rx2;
>
> /**
> * @param {string} s
> * @param {jsx.regexp.RegExp} rx
> * Instance to be tested
> * @return {boolean}
^^^^^^^^^
> * <code>true</code> if <var>rx</var> has been constructed
> * using this constructor, <code>false</code> otherwise.
JFTR: As you can see further below, this is a documentation bug that will be
fixed in the next revision. The return value of the custom method is
exactly what the original RegExp.prototype.exec() method would have had
returned (“null” or a reference to an Array-like object), augmented with
custom properties if there is a match.
--
PointedEars
Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.javascript
csiph-web