Global regex replace is failing to replace the initial occurrence

In my attempt to create a simple template test, I encountered an issue with regular expressions. Despite using the \g modifier, only the last occurrence is being replaced instead of all copies.

(How to String.match() distinct it ${SOME_TEXT} using Regex)

My goal is to prompt the user once for each unique variable name.

Title = t
name = n
result = '${Title} - n - t'

The pattern /\$\{([^\}]+)\}/g works but results in multiple prompts for the user.

Title = t
name = n
Title = t
result = 't - n - t'

Is there a way to replace each token with a single value regardless of how many times it appears?

<html>
<head>
    <script type="application/javascript">

        window.copyToClipboard = function(n) {
            var u = "_hiddenCopyText_", t, i, r;
            t = document.getElementById(u);
            t.textContent = n;
            i = document.activeElement;
            t.focus();
            t.setSelectionRange(0, t.value.length);
            try {
                r = document.execCommand("copy")
            } catch (f) {
                r = !1
            }
            return i && typeof i.focus == "function" && i.focus(),
                t.textContent = "",
                r
        };
        //${varname}
        window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g;
        window.test = " ${Title} - ${Name} - ${Title}"
        window.copyTemplate = function (template) {
            var result = template.replace(window.templateRegex, function(match, token){
               return window.prompt("replace value for ${"+token+"}","${"+token+"}");
            });
            window.copyToClipboard(result);
        };

    </script>
</head>
<textarea id="_hiddenCopyText_"></textarea>
<button onclick="copyTemplate(window.test)">Test</button>
</html>

JsFiddle https://jsfiddle.net/ksu37c3b/

Answer №1

When the same ${..}(${Title}) appears multiple times, the regular expression

/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g
will only match the last occurrence. To match all elements, you can use /\$\{([^\}]+)\}/g, which does not require the negative lookahead (?![\S\s]*\$\{\1\}).
In the string
"${Title} - ${Name} - ${Title}"
, only ${Name} and ${Title} match the pattern because the first and last occurrences are the same. If the string is modified to something like
"${Title2} - ${Name} - ${Title}"
, all elements will be matched since ${Title2} and ${Title} are different. The purpose of (?![\S\s]*\$\{\1\}) is to ensure that consecutive identical tokens are not matched.

update

How can I replace each token with a single value regardless of the number of occurrences?

You can utilize the match() method to retrieve an array of tokens and then replace them one by one. The following code demonstrates this:

window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g;
window.test = " ${Title} - ${Name} - ${Title}";
var userinput, reg, i;
var arr = window.test.match(/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g);
for (i = 0; i < arr.length; i++) {
    arr[i] = arr[i].replace(/[\$\{\}]/g, "");
    userinput = window.prompt("replace value for " + arr[i]);
    reg = new RegExp("\\$\\{" + arr[i] + "\\}", 'g');
    console.log(reg);
    window.test = window.test.replace(reg, userinput);
}
alert(window.test);

I have made some modifications to your code as shown below:

window.copyToClipboard = function(n) {
  var u = "_hiddenCopyText_",
    t, i, r;
  t = document.getElementById(u);
  t.textContent = n;
  //** snip **//
};
//${varname}
window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g;
window.test = " ${Title} - ${Name} - ${Title}";
window.copyTemplate = function(template) {
    var result = template;
    var userinput, reg;
    var arr = result.match(/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g);
    for (let i = 0; i < arr.length; i++) {
        arr[i] = arr[i].replace(/[\$\{\}]/g, "");
        userinput = window.prompt("replace value for " + arr[i]);
        reg = new RegExp("\\$\\{" + arr[i] + "\\}", 'g');
        console.log(reg);
        result = result.replace(reg, userinput);
    }
    window.copyToClipboard(result);
};
<textarea id="_hiddenCopyText_"></textarea>
<button onclick="copyTemplate(window.test)">Test</button>​

Answer №2

Try using this regex pattern to achieve the desired result:

/\$\{([^\}]+)\}(?![\S\s]\$\{\1\})/

I made a modification by omitting the * within the negative look ahead, as it was leading to a match with the last occurrence consistently.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Best Practices for Storing Static JSON Data in a Chrome Extension

In my extension, I have a collection of around 350 lines of static JSON data. This data is essential for the functioning of a content script, as it consists of key-value pairs that are checked upon user interaction to trigger specific actions. Here's ...

Exploring the concept of 'JavaScript with Scope' within the MongoDB environment

Within the link provided at https://docs.mongodb.com/manual/reference/bson-types/, it discusses JavaScript with Scope as a potential data type found in documents. I have some inquiries: (1) Could you explain what exactly JavaScript with scope entails? ( ...

Vanilla JavaScript // Conceal a div when the class of another div is modified

Note: I am unable to utilize jQuery, only vanilla JavaScript I am not very proficient in pure JS. Additionally, this time around, I cannot rely on any external resources such as jQuery. What I am looking for: If the div1 class is active, I want to hide ...

The error message TS2322 in MUI v5 states that the property 'fullWidth' is not found in the type 'IntrinsicAttributes & { theme: Theme; } & { children?: ReactNode; }'

As a user of MUI v5, I have implemented a straightforward FormControl as seen below. It is important to note that the property fullWidth is supported according to the official documentation. import React, { PropsWithChildren } from 'react' import ...

Is it possible for the Observable call in Angular 4 to function similarly to jQuery's synchronous AJAX method?

As I have a business logic function that needs to use HttpGet and I must wait for the result before continuing, jQuery's ajax can handle this easily. But I am curious if Observables have a similar feature? I was hoping for the result to be: John An ...

Float over a specific line in a drawing

I am looking to develop a unique rating system using css, html, and potentially js : https://i.sstatic.net/pQP79.png My goal is for the user to hover over a specific section of a circular stroke and have it fill with a particular color, all while maintai ...

Stop the setTimeout function after redirecting in the controller

I am experiencing an issue with my AJAX call as it keeps triggering my controller repeatedly. AJAX function <script type="text/javascript> var stopTime =0; var scoreCheck = function () { $.ajax({ url: "<?php echo 'http:// ...

The TypeORM connection named "default" could not be located during the creation of the connection in a Jest globalSetup environment

I've encountered a similar issue as the one discussed in #5164 and also in this thread. Here is a sample of working test code: // AccountResolver.test.ts describe('Account entity', () => { it('add account', async () => { ...

What could be causing my images not to show up when I use string interpolation for src links in Vue.js?

I've encountered an issue while working on Vue.js where I'm struggling to render a couple of images from the local directory. What puzzles me is that this problem arises when using string interpolation, like in the code snippet below: <img :s ...

Utilize a for loop to load data using JSON

Here's a question for you. Take a look at my code snippet: var data=[]; for(i=0;i<parametrTable.length;++i){ x = parametrTable[i]; (function(i) { if(i==0){ $.getJSON("myurlwithparametr", function(json) { ...

The lack of definition for the props value poses an issue in React.js Hooks

I'm currently developing a notepad web application that utilizes React Hooks for managing state variables. In order to fetch data from an API, I am using the axios library. The retrieved data consists of objects with fields such as _id, title, status, ...

Build a basic website featuring a left-side menu and content on the right side

I intend to design a straightforward website featuring: A left menu with clickable items Clicking on each item will change the right menu to display new content consisting of a title, picture 1, text description, and picture 2. This format will be consis ...

Encountering an NPM error while attempting to initiate a new React application

Having trouble creating a React app due to an npm warning message? Seek assistance, please! npm WARN deprecated <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="19342d2e6a6867687c4b">[email protected]</a>: This ve ...

Using Nuxt and Cloudinary to seamlessly upload images from the client side directly to the Cloudinary platform

Is there a way to directly upload images from my Nuxt (vue) app to Cloudinary without involving a server? I've been searching for information on how to accomplish this but haven't found any concrete solutions. <v-file-input v-else ...

Does the Error page in Next JS 13 fail to properly manage fetch API errors?

After referencing the documentation for Next.js with app router, I followed the instructions to create an error.tsx page within my app folder (app/[lang]/error.tsx). This file contains the code provided in the docs. Additionally, I included some API calls ...

Preventing AngularJS from Binding in Rows: A Solution

Currently, I am utilizing AngularJS version 1.5.3 and I am facing an issue with my services. I have two services - one that retrieves Area names and the other that fetches details for each Area. In my code, I first call the service to get the Area names an ...

My JavaScript if-else statement isn't functioning properly

I'm facing an issue with my if statement not functioning correctly when trying to validate non-numeric inputs for the weight variable upon submission. What could be causing this problem? submitBtn.onclick = function(){ var name = document.get ...

How can you interact between a parent's named controller and JavaScript files in AngularJS?

Lately, I've been exploring the use of named controllers in my code and find it to be a much better alternative to using traditional $scope variables. It makes accessing parent controller attributes and functions within the DOM seamless. See an exampl ...

I have encountered a node.js error related to the 'Require Stack'

Encountering an error in my node.js application when trying to open a .js file { code: 'MODULE_NOT_FOUND', requireStack: } Unable to determine the root cause of this issue I have tried re-installing Node.js and its packages, removed and added b ...

What are the advantages of using React JS for a Single Page Application compared to server-side rendering?

Currently, I am faced with a conundrum when it comes to selecting the best approach for a highly scalable project. On one hand, server-side rendering using Node.js with Express (utilizing EJS) to render full HTML pages is an option. On the other hand, ther ...