0

What I would like to do is read through the file like the one below and save all the function names into an array using regex. The function names I would like to save would be 'firstCall', 'SecondCall'. Ive tested the regex pattern and it seems to be working. But the issue is how do I use the regex pattern to search through the data from the text file I read before? If this is impossible would I be able to do the following task using maybe shell script?

function firstCall(){
    some random logic
}


function SecondCall(data){
    some other random logic
}

So far I have the following code where it would take the filename as an argument and then use readFile to search through that file. I wanted to be able to run this script on a terminal, which is why I have the file name passed in as an argument.

const fs = require("fs");

let fileName = process.argv[2];

const reg_pattern = /(?<=function )s*[a-zA-Z]*/g;

console.log(fileName);

fs.readFile(fileName, (err, data) => {
  if (err) throw err;
  let functionName = reg_pattern.exec(data);
  //let functionName_2 = data.match(reg_pattern);
  console.log(functionName);
});

This is what the output looks like as of now. The first position of the array is 'firstCall' but the rest doesn't seem to look right. Im not really sure whats going wrong.

$ node testing.js testing.txt
testing.txt
[
  'firstCall',
  index: 9,
  input: 'function firstCall(){\r\n' +
    '    some random logic\r\n' +
    '}\r\n' +
    '\r\n' +
    '\r\n' +
    'function SecondCall(data){\r\n' +
    '    some other random logic\r\n' +
    '}',
  groups: undefined
]
Freakup2
  • 3
  • 3
  • You need to pass the `'g'` flag as the second argument when creating the regex if you want it to match more than once. Use `reg_pattern.exec()` to iterate through the matches. – murrayju Jul 14 '20 at 02:53
  • @murrayju i just updated my question. I tried it with the /g command at the end and I have posted the output I got. Doesn't seem to get the second function name. – Freakup2 Jul 14 '20 at 03:05
  • I just posted an answer with complete details. `exec()` only returns one match at a time, you have to call it in a loop. In my answer, I suggest using the newer `matchAll()` (if it is available on your platform). – murrayju Jul 14 '20 at 03:29

2 Answers2

0

From RegEx to extract all matches from string using RegExp.exec

const fs = require("fs");

let fileName = process.argv[1];

const reg_pattern = new RegExp("(?<=function )s*[a-zA-Z]*");

console.log(fileName);

fs.readFile(fileName, (err, data) => {
  if (err) throw err;

  do {
    m = reg_pattern.exec(data);
    if (m) {
      console.log(m);
    }
  } while (m);
});

Also, you should consider using another library, such as babel to do this query as regular expressions aren't flexible enough for parsing javascript, as well as adding another point of failure into your application.

Elias Schablowski
  • 2,619
  • 9
  • 19
  • The do while seems to work. I had to change the regex to have capture groups like @murrayju mentioned and it seems to be working fine for now. Im pretty new to js and might need some time reading up on babel to try using its parsing. – Freakup2 Jul 14 '20 at 03:59
0

If you are using node.js v12 or newer, then you can use the convenient String.prototype.matchAll() instead of exec().

I don't think that the RegExp you provided will work. It is important to use parenthesis to create a capture group around the part of the pattern that you want to do something with. I also took some liberties to improve it slightly to be slightly more robust.

The below works fine for your sample input, but I would not expect this to work for all possible function declarations. This is fine if you have fairly controlled input, but isn't a general solution for parsing JavaScript. To do that, you'd have to write a proper parser. RegExps are not powerful enough to parse programming languages, you would need to use a grammar with a tool like ANTLR.

const fs = require("fs");
const fileName = process.argv[1];

// shorthand regex syntax
const regex = /\bfunction\s+([a-zA-Z]\w*)\s*\(/g;

fs.readFile(fileName, (err, data) => {
  if (err) throw err;

  // This returns an iterator
  const matches = data.matchAll(regex);

  for (const match of matches) {
    // match is an object containing all info about the matched expression
    // match[1] is the first capture group (the function name)
    console.log(match[1]);
  }
});

Here is a demo on RunKit.

murrayju
  • 1,752
  • 17
  • 21
  • Sadly the server is using node 8.9 so the matchAll() wont be working. The grouping is actually usefully and it seems to be working on the file i'm testing right now. For now i think i'll stick with regex and then try to work my self up to parsing. I have zero clue about parsing as of now lol. – Freakup2 Jul 14 '20 at 03:57