LexJacobs
LexJacobs

Reputation: 2533

Recombine capture groups in single regexp?

I am trying to handle input groups similar to:

'...A.B.' and want to output '.....AB'.

Another example:

'.C..Z..B.' ==> '......CZB'

I have been working with the following:

'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1")

returns:

"....."

and

'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")

returns:

"AB"

but

'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1$2")

returns

"...A.B."

Is there a way to return

"....AB"

with a single regexp?

I have only been able to accomplish this with:

'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1") + '...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")

==> ".....AB"

Upvotes: 3

Views: 39

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074335

If the goal is to move all of the . to the beginning and all of the A-Z to the end, then I believe the answer to

with a single regexp?

is "no."

Separately, I don't think there's a simpler, more efficient way than two replace calls — but not the two you've shown. Instead:

var str = "...A..B...C.";
var result = str.replace(/[A-Z]/g, "") + str.replace(/\./g, "");
console.log(result);

(I don't know what you want to do with non-., non-A-Z characters, so I've ignored them.)

If you really want to do it with a single call to replace (e.g., a single pass through the string matters), you can, but I'm fairly sure you'd have to use the function callback and state variables:

var str = "...A..B...C.";
var dots = "";
var nondots = "";
var result = str.replace(/\.|[A-Z]|$/g, function(m) {
  if (!m) {
    // Matched the end of input; return the
    // strings we've been building up
    return dots + nondots;
  }
  // Matched a dot or letter, add to relevant
  // string and return nothing
  if (m === ".") {
    dots += m;
  } else {
    nondots += m;
  }
  return "";
});
console.log(result);

That is, of course, incredibly ugly. :-)

Upvotes: 1

Related Questions