I'm having a little trouble with while loops in coffeescript.
The original function is as the following and the source is this answer:
// Return all pattern matches with captured groups
RegExp.prototype.execAll = function(string) {
var match = null;
var matches = new Array();
while (match = this.exec(string)) {
var matchArray = [];
for (i in match) {
if (parseInt(i) == i) {
matchArray.push(match[i]);
}
}
matches.push(matchArray);
}
return matches;
}
It works as intended. I have converted it via js2coffee and the coffee script is:
# Return all pattern matches with captured groups
RegExp::execAll = (string) ->
matches = new Array()
match = null
while match = @exec(string)
matchArray = new Array()
for i of match
matchArray.push match[i] if parseInt(i) is i
matches.push matchArray
matches
Which compiles to:
RegExp.prototype.execAll = function(string) {
var i, match, matchArray, matches;
matches = new Array();
match = null;
while (match = this.exec(string)) {
matchArray = new Array();
for (i in match) {
if (parseInt(i) === i) {
matchArray.push(match[i]);
}
}
matches.push(matchArray);
}
return matches;
};
The result is:
[
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
I think this doesn't work because of the variable scope since the only difference I can see is this line:
RegExp.prototype.execAll = function(string) {
var i, match, matchArray, matches;
versus the original:
RegExp.prototype.execAll = function(string) {
var match = null;
var matches = new Array();
while (match = this.exec(string)) {
var matchArray = [];
Notice how matchArray is scoped out... I couldn't find a way around this, but as I was researching I found these questions Were `do...while` loops left out of CoffeeScript...? and How do I declare a variable in a specific scope in coffeescript? and I'm pretty much out of ideas here... Any other way of matching all with regexp other than this while loop (by the way I have tried \gm flags and it still hits only one match)? Or is there a way of getting this scope right in coffee script?
The whole Coffee Script code is :
fs = require 'fs'
text = fs.readFileSync('test.md','utf8')
#console.log text
regex = /^(?:@@)(\w+):(.*.)/gm
# Return all pattern matches with captured groups
RegExp::execAll = (string) ->
matches = new Array()
match = null
while match = @exec(string)
matchArray = new Array()
for i of match
matchArray.push match[i] if parseInt(i) is i
matches.push matchArray
matches
res = regex.execAll text
#console.log regex.exec text
console.log (JSON.stringify(res, null, " ") )
And the Javascript that works is this:
var fs, regex, res, text;
fs = require('fs');
text = fs.readFileSync('test.md', 'utf8');
regex = /^(?:@@)(\w+):(.*.)/gm;
// Return all pattern matches with captured groups
RegExp.prototype.execAll = function(string) {
var match = null;
var matches = new Array();
while (match = this.exec(string)) {
var matchArray = [];
for (i in match) {
if (parseInt(i) == i) {
matchArray.push(match[i]);
}
}
matches.push(matchArray);
}
return matches;
}
res = regex.execAll(text);
//console.log(regex.exec(text));
console.log(JSON.stringify(res, null, " "));
The actual problem is not what you think it is. The actual problem is that the == compiled to ===. Here's how you fix it:
# Return all pattern matches with captured groups
RegExp::execAll = (string) ->
matches = []
while match = @exec string
matches.push(group for group in match)
matches
But you may be wondering why === doesn't work. Thus, I present to you:
=== doesn't work (in this case)parseInt(i) == i was supposed to determine if i is a string that represents an integer. You can try that in JavaScript on a few values and see that it works. parseInt(i) is a number, whereas i is a string. In JavaScript, if you're using == on a string and a number, it will implicitly coerce and the test will work as you might expect. This implicit coercion is often unexpected, so CoffeeScript disallows it from happening by having no equivalent of the == operator, translating == (and is) into ===, which first compares types. In that case, the number and the string will never be equal, so the if's condition is never met, so nothing is ever pushed onto the array.