therks
therks

Reputation: 528

Regular expression replacement next to number

Sorry if this has been answered already. I tried to look for it but maybe I can't figure out how to word my question properly.

Making a little HTML app with a simple regular expression replacement processor. User can input: text, regex pattern, replacement pattern. Running into a snag if more than 9 groups are used though and the user wants to place a number beside the group.

Example:

This would return J, but what if the user wants to return A0? How can we replace with $1 0 without a space in between?

The gist of my code is thus:

let input = document.querySelector('#input').value
let regex = eval(document.querySelector('#pattern').value)
let replacement = document.querySelector('#replacement').value
document.querySelector('#output').value = input.replace(regex, replacement)

I'm doing a little more error checking and processing than that, but you get the point.

app screenshot

Upvotes: 4

Views: 576

Answers (2)

Scruffy
Scruffy

Reputation: 580

When you encounter a $ in the replacement you might:

  1. if the previous character was a \, treat this a real $ rather than introducing a capture-group reference,
  2. if the next character is a digit, do as you do currently and treat it as a single-digit integer indexing CG references,
  3. if the next character is a {, find the matching } and parse the integer between them and again use that to index the capture groups in the regex.

This way the user can write $9 or ${9} but also ${10}.

Upvotes: 3

CertainPerformance
CertainPerformance

Reputation: 370619

The situation sounds somewhat ambiguous. If the user inputs $10 and is using a pattern with that many groups, I'd think the user likely wants to use the 10th capture group. If they don't, the user shouldn't have 10 capture groups in the first place.

But if you really want to prevent double digits after a $ from going to the double-digit capture group, it's a bit hacky, but you can add another capture group that matches the empty string, and then replace the user's pattern to remove the consecutive $\d\ds, and insert the empty string matcher in between.

For example, $10 can be transformed into $1$<nomatch>0.

I don't see anything clean in the specification that allows for the escaping of or breaking out of consecutive digits after a $, or of the guaranteed general replacement with an empty string without tweaking the input pattern.

There's also no need for eval.

const value = '$10';

const patternValue = '(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)';
const pattern = new RegExp(patternValue + '|(?<nomatch>)');
const replacement =
  // document.querySelector('#pattern').value.replace(
  value.replace(
    /\$\d(?=\d)/g,
    '$&$<nomatch>'
  );
console.log(pattern);
console.log(replacement);
console.log('ABCDEFGHIJ'.replace(pattern, replacement));

But like I said initially, this is a weird thing to want to achieve. A user using $10 with a pattern that has 10 capture groups really probably wants to actually use the 10th capture group.

Upvotes: 3

Related Questions