Home > Mobile >  Why my regex doesn't capture the tracking expression in the string?
Why my regex doesn't capture the tracking expression in the string?

Time:12-26

I try to parse the ng-repeat expressions from angularjs into a structured object using regex:

const ngRepeatExpressions = [
  "key, value in items track by key",
  "item in items",
  "item in items track by item.id"
];

I created this regex that extracts the variables and logs the expressions captured from the string:

const regex = /\s*(. )\s in\s (. )(?:\s track\s by\s (. ))?/;

This regular expression has three capture groups:

  1. The first capture group ((. )) captures the variable that represents each item in the collection. If the ng-repeat expression uses the syntax key, value in items, this capture group will capture both the key and value variables.
  2. The second capture group ((. )) captures the collection that is being iterated over.
  3. The third capture group ((. )) captures the tracking expression, if present. If the track by clause is not present, this capture group will not be populated.

Here is the snippet:

const ngRepeatExpressions = [
  'key, value in items track by key',
  'item in items',
  'item in items track by item.id',
];
const regex = /\s*(. )\s in\s (. )(?:\s track\s by\s (. ))?/;
ngRepeatExpressions.forEach((expression) => {
  const [, variables, collection, trackingExpression] = expression.match(regex);
  console.log({variables, collection, trackingExpression});
});

But when I run this code, I see the trackingExpression variable is always undefined.

Why? The regex doesn't match the third capture group ((. ))? How I need to change my regex so it matches the right trackingExpression and collection?

CodePudding user response:

The problem is the greedy . in the second capture group, which will read all up to the end of the input string. Because the last part is optional, it doesn't need to backtrack.

A solution is to make that second capture group non-greedy (lazy), and require that the whole input is matched, using ^ and $ anchors:

const regex = /^\s*(. )\s in\s (. ?)(?:\s track\s by\s (. ))?$/;

Updated snippet:

const ngRepeatExpressions = [
  'key, value in items track by key',
  'item in items',
  'item in items track by item.id',
];
const regex = /^\s*(. )\s in\s (. ?)(?:\s track\s by\s (. ))?$/;
ngRepeatExpressions.forEach((expression) => {
  const [, variables, collection, trackingExpression] = expression.match(regex);
  console.log({variables, collection, trackingExpression});
});

  • Related