Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder4.news.weretis.net!newsfeed.fsmpi.rwth-aachen.de!uucp.gnuu.de!newsfeed.arcor.de!newsspool2.arcor-online.net!news.arcor.de.POSTED!not-for-mail Content-Type: text/plain; charset="UTF-8" Message-ID: <3573991.qt74eh6WeI@PointedEars.de> From: Thomas 'PointedEars' Lahn Reply-To: Thomas 'PointedEars' Lahn Organization: PointedEars Software (PES) Date: Fri, 30 Aug 2013 16:00:57 +0200 User-Agent: KNode/4.10.5 Content-Transfer-Encoding: 8Bit X-Face: %i>XG-yXR'\"2P/C_aO%~;2o~?g0pPKmbOw^=NT`tprDEf++D.m7"}HW6.#=U:?2GGctkL,f89@H46O$ASoW&?s}.k+&. MIME-Version: 1.0 Lines: 173 NNTP-Posting-Date: 30 Aug 2013 16:01:09 CEST NNTP-Posting-Host: 8863c66d.newsspool2.arcor-online.net X-Trace: DXC=jmRD`?hO4IDA@P]\DA9EHlD;3YcB4Fo<]lROoRA8kF 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 + '
'); | }); | | 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: /* ? style; also supports ?'Perl' style and ?P style */ var regex = new jsx.regexp.RegExp("^(?.+?): (?.+)$", "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} * true if rx has been constructed * using this constructor, false 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 for more. -- PointedEars Twitter: @PointedEars2 Please do not Cc: me. / Bitte keine Kopien per E-Mail.